Skip to content

Commit bda30a3

Browse files
committed
pull from upstream
2 parents 8561326 + 08d1291 commit bda30a3

File tree

7 files changed

+509
-5
lines changed

7 files changed

+509
-5
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,3 +123,6 @@ docker-compose.y*ml
123123
# vscode settings
124124
.vscode
125125
*.code-workspace
126+
127+
# exports/notes
128+
temp*

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ Observes [Semantic Versioning](https://semver.org/spec/v2.0.0.html) standard and
1414
+ Update - clustering step, update duration for "median_subtraction" step
1515
+ Bugfix - handles single probe recording in "Neuropix-PXI" format
1616
+ Update - safeguard in creating/inserting probe types upon probe activation
17+
+ Add - quality control metric dashboard
1718

1819
## [0.2.0] - 2022-10-28
1920

element_array_ephys/ephys_report.py

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import datetime
22
import pathlib
3+
from uuid import UUID
34

45
import datajoint as dj
6+
from element_interface.utils import dict_to_uuid
57

68
from . import probe
79

@@ -153,6 +155,94 @@ def make(self, key):
153155
)
154156

155157

158+
@schema
159+
class QualityMetricCutoffs(dj.Lookup):
160+
definition = """
161+
cutoffs_id : smallint
162+
---
163+
amplitude_cutoff_maximum=null : float # Defualt null, no cutoff applied
164+
presence_ratio_minimum=null : float # Defualt null, no cutoff applied
165+
isi_violations_maximum=null : float # Defualt null, no cutoff applied
166+
cutoffs_hash: uuid
167+
unique index (cutoffs_hash)
168+
"""
169+
170+
contents = [
171+
(0, None, None, None, UUID("5d835de1-e1af-1871-d81f-d12a9702ff5f")),
172+
(1, 0.1, 0.9, 0.5, UUID("f74ccd77-0b3a-2bf8-0bfd-ec9713b5dca8")),
173+
]
174+
175+
@classmethod
176+
def insert_new_cutoffs(
177+
cls,
178+
cutoffs_id: int = None,
179+
amplitude_cutoff_maximum: float = None,
180+
presence_ratio_minimum: float = None,
181+
isi_violations_maximum: float = None,
182+
):
183+
if cutoffs_id is None:
184+
cutoffs_id = (dj.U().aggr(cls, n="max(cutoffs_id)").fetch1("n") or 0) + 1
185+
186+
param_dict = {
187+
"amplitude_cutoff_maximum": amplitude_cutoff_maximum,
188+
"presence_ratio_minimum": presence_ratio_minimum,
189+
"isi_violations_maximum": isi_violations_maximum,
190+
}
191+
param_hash = dict_to_uuid(param_dict)
192+
param_query = cls & {"cutoffs_hash": param_hash}
193+
194+
if param_query: # If the specified cutoff set already exists
195+
existing_paramset_idx = param_query.fetch1("cutoffs_id")
196+
if (
197+
existing_paramset_idx == cutoffs_id
198+
): # If the existing set has the same id: job done
199+
return
200+
# If not same name: human err, adding the same set with different name
201+
else:
202+
raise dj.DataJointError(
203+
f"The specified param-set already exists"
204+
f" - with paramset_idx: {existing_paramset_idx}"
205+
)
206+
else:
207+
if {"cutoffs_id": cutoffs_id} in cls.proj():
208+
raise dj.DataJointError(
209+
f"The specified cuttoffs_id {cutoffs_id} already exists,"
210+
f" please pick a different one."
211+
)
212+
cls.insert1(
213+
{"cutoffs_id": cutoffs_id, **param_dict, "cutoffs_hash": param_hash}
214+
)
215+
216+
217+
@schema
218+
class QualityMetricSet(dj.Manual):
219+
definition = """
220+
-> ephys.QualityMetrics
221+
-> QualityMetricCutoffs
222+
"""
223+
224+
225+
@schema
226+
class QualityMetricReport(dj.Computed):
227+
definition = """
228+
-> QualityMetricSet
229+
---
230+
plot_grid : longblob
231+
"""
232+
233+
def make(self, key):
234+
from .plotting.qc import QualityMetricFigs
235+
236+
cutoffs = (QualityMetricCutoffs & key).fetch1()
237+
qc_key = ephys.QualityMetrics & key
238+
239+
self.insert1(
240+
key.update(
241+
dict(plot_grid=QualityMetricFigs(qc_key, **cutoffs).get_grid().to_json)
242+
)
243+
)
244+
245+
156246
def _make_save_dir(root_dir: pathlib.Path = None) -> pathlib.Path:
157247
if root_dir is None:
158248
root_dir = pathlib.Path().absolute()

0 commit comments

Comments
 (0)