14
14
15
15
16
16
def activate (ephys_schema_name , probe_schema_name = None , create_schema = True , create_tables = True , add_objects = None ):
17
- upstream_tables = ("Session" , "SkullReference" )
18
17
assert isinstance (add_objects , Mapping )
18
+
19
+ upstream_tables = ("Session" , "SkullReference" )
19
20
try :
20
21
raise RuntimeError ("Table %s is required for module ephys" % next (
21
22
name for name in upstream_tables
22
- if not isinstance (add_objects .get (name , None ), (dj .Manual , dj .Lookup , dj .Imported , dj .Computed ))))
23
+ if not isinstance (add_objects .get (name , None ), (dj .Manual , dj .Lookup , dj .Imported , dj .Computed , dj . user_tables . OrderedClass ))))
23
24
except StopIteration :
24
25
pass # all ok
25
26
26
27
required_functions = ("get_neuropixels_data_directory" , "get_paramset_idx" , "get_kilosort_output_directory" )
27
- assert isinstance (add_objects , Mapping )
28
28
try :
29
29
raise RuntimeError ("Function %s is required for module ephys" % next (
30
30
name for name in required_functions
31
31
if not inspect .isfunction (add_objects .get (name , None ))))
32
32
except StopIteration :
33
33
pass # all ok
34
34
35
- if not probe .schema .is_activated :
35
+ if not probe .schema .database :
36
36
probe .schema .activate (probe_schema_name or ephys_schema_name ,
37
37
create_schema = create_schema , create_tables = create_tables )
38
+
38
39
schema .activate (ephys_schema_name , create_schema = create_schema ,
39
40
create_tables = create_tables , add_objects = add_objects )
40
41
41
42
42
43
# REQUIREMENTS: The workflow module must define these functions ---------------
43
44
44
45
45
- def get_neuropixels_data_directory ():
46
- return None
46
+ def get_neuropixels_data_directory (probe_insertion_key : dict ) -> str :
47
+ """
48
+ Retrieve the recorded Neuropixels data directory for a given ProbeInsertion
49
+ :param probe_insertion_key: a dictionary of one ProbeInsertion `key`
50
+ :return: a string for full path to the resulting Neuropixels data directory
51
+ """
52
+ assert set (ProbeInsertion ().primary_key ) <= set (probe_insertion_key )
53
+ raise NotImplementedError ('Workflow module should define function: "get_neuropixels_data_directory"' )
47
54
48
55
49
56
def get_kilosort_output_directory (clustering_task_key : dict ) -> str :
50
57
"""
51
58
Retrieve the Kilosort output directory for a given ClusteringTask
52
- :param clustering_task_key: a dictionary of one EphysRecording
59
+ :param clustering_task_key: a dictionary of one ClusteringTask `key`
53
60
:return: a string for full path to the resulting Kilosort output directory
54
61
"""
55
62
assert set (EphysRecording ().primary_key ) <= set (clustering_task_key )
56
- raise NotImplementedError ('Workflow module should define' )
63
+ raise NotImplementedError ('Workflow module should define function: "get_kilosort_output_directory" ' )
57
64
58
65
59
66
def get_paramset_idx (ephys_rec_key : dict ) -> int :
60
67
"""
61
- Retrieve attribute `paramset_idx` from the ClusteringParamSet record for the given EphysRecording key .
62
- :param ephys_rec_key: a dictionary of one EphysRecording
68
+ Retrieve attribute `paramset_idx` from the ClusteringParamSet record for the given EphysRecording.
69
+ :param ephys_rec_key: a dictionary of one EphysRecording `key`
63
70
:return: int specifying the `paramset_idx`
64
71
"""
65
72
assert set (EphysRecording ().primary_key ) <= set (ephys_rec_key )
66
- raise NotImplementedError ('Workflow module should define' )
73
+ raise NotImplementedError ('Workflow module should define function: get_paramset_idx ' )
67
74
68
75
69
- def dict_to_uuid (key ):
70
- """
71
- Given a dictionary `key`, returns a hash string
72
- """
73
- hashed = hashlib .md5 ()
74
- for k , v in sorted (key .items ()):
75
- hashed .update (str (k ).encode ())
76
- hashed .update (str (v ).encode ())
77
- return uuid .UUID (hex = hashed .hexdigest ())
78
-
79
76
# ===================================== Probe Insertion =====================================
80
77
81
78
@@ -109,17 +106,13 @@ class InsertionLocation(dj.Manual):
109
106
110
107
111
108
# ===================================== Ephys Recording =====================================
112
- # The abstract function _get_neuropixels_data_directory() should expect one argument in the form of a
113
- # dictionary with the keys from user-defined Subject and Session, as well as
114
- # "insertion_number" (as int) based on the "ProbeInsertion" table definition in this djephys
115
-
116
109
117
110
@schema
118
111
class EphysRecording (dj .Imported ):
119
112
definition = """
120
113
-> ProbeInsertion
121
114
---
122
- -> ElectrodeConfig
115
+ -> probe. ElectrodeConfig
123
116
sampling_rate: float # (Hz)
124
117
"""
125
118
@@ -143,7 +136,7 @@ def make(self, key):
143
136
neuropixels_meta .probe_model ))
144
137
145
138
# ---- compute hash for the electrode config (hash of dict of all ElectrodeConfig.Electrode) ----
146
- ec_hash = uuid . UUID ( dict_to_uuid ({k ['electrode' ]: k for k in eg_members }) )
139
+ ec_hash = dict_to_uuid ({k ['electrode' ]: k for k in eg_members })
147
140
148
141
el_list = sorted ([k ['electrode' ] for k in eg_members ])
149
142
el_jumps = [- 1 ] + np .where (np .diff (el_list ) > 1 )[0 ].tolist () + [len (el_list ) - 1 ]
@@ -185,7 +178,7 @@ class Electrode(dj.Part):
185
178
"""
186
179
187
180
def make (self , key ):
188
- neuropixels_dir = EphysRecording . _get_neuropixels_data_directory (key )
181
+ neuropixels_dir = get_neuropixels_data_directory (key )
189
182
neuropixels_recording = neuropixels .Neuropixels (neuropixels_dir )
190
183
191
184
lfp = neuropixels_recording .lfdata [:, :- 1 ].T # exclude the sync channel
@@ -201,7 +194,7 @@ def make(self, key):
201
194
q_electrodes = probe .ProbeType .Electrode * probe .ElectrodeConfig .Electrode & key
202
195
electrodes = []
203
196
for recorded_site in np .arange (lfp .shape [0 ]):
204
- shank , shank_col , shank_row , _ = neuropixels_recording .neuropixels_meta .shankmap ['data' ][recorded_site ]
197
+ shank , shank_col , shank_row , _ = neuropixels_recording .npx_meta .shankmap ['data' ][recorded_site ]
205
198
electrodes .append ((q_electrodes
206
199
& {'shank' : shank ,
207
200
'shank_col' : shank_col ,
@@ -269,14 +262,15 @@ class ClusteringTask(dj.Imported):
269
262
"""
270
263
271
264
def make (self , key ):
272
- key ['paramset_idx' ] = ClusteringTask ._get_paramset_idx (key )
273
- self .insert1 (key )
265
+ key ['paramset_idx' ] = get_paramset_idx (key )
274
266
275
- data_dir = pathlib .Path (ClusteringTask . _get_ks_data_dir (key ))
267
+ data_dir = pathlib .Path (get_kilosort_output_directory (key ))
276
268
if not data_dir .exists ():
277
269
# this is where we can trigger the clustering job
278
270
print (f'Clustering results not yet found for { key } - Triggering kilosort not yet implemented!' )
279
271
272
+ self .insert1 (key )
273
+
280
274
281
275
@schema
282
276
class ClusterQualityLabel (dj .Lookup ):
@@ -319,7 +313,7 @@ class Unit(dj.Part):
319
313
"""
320
314
321
315
def make (self , key ):
322
- ks_dir = ClusteringTask . _get_ks_data_dir (key )
316
+ ks_dir = get_kilosort_output_directory (key )
323
317
ks = kilosort .Kilosort (ks_dir )
324
318
# ---------- Clustering ----------
325
319
creation_time , is_curated , is_qc = kilosort .extract_clustering_info (ks_dir )
@@ -462,7 +456,7 @@ def make(self, key):
462
456
463
457
464
458
def get_neuropixels_chn2electrode_map (ephys_recording_key ):
465
- neuropixels_dir = EphysRecording . _get_neuropixels_data_directory (ephys_recording_key )
459
+ neuropixels_dir = get_neuropixels_data_directory (ephys_recording_key )
466
460
meta_filepath = next (pathlib .Path (neuropixels_dir ).glob ('*.ap.meta' ))
467
461
neuropixels_meta = neuropixels .NeuropixelsMeta (meta_filepath )
468
462
e_config_key = (EphysRecording * probe .ElectrodeConfig & ephys_recording_key ).fetch1 ('KEY' )
@@ -475,3 +469,14 @@ def get_neuropixels_chn2electrode_map(ephys_recording_key):
475
469
'shank_col' : shank_col ,
476
470
'shank_row' : shank_row }).fetch1 ('KEY' )
477
471
return chn2electrode_map
472
+
473
+
474
+ def dict_to_uuid (key ):
475
+ """
476
+ Given a dictionary `key`, returns a hash string
477
+ """
478
+ hashed = hashlib .md5 ()
479
+ for k , v in sorted (key .items ()):
480
+ hashed .update (str (k ).encode ())
481
+ hashed .update (str (v ).encode ())
482
+ return uuid .UUID (hex = hashed .hexdigest ())
0 commit comments