@@ -95,14 +95,24 @@ def _channels_traj2bunch(xyz_chans, brain_atlas):
9595 return channels
9696
9797
98+ def _channels_bunch2alf (channels ):
99+ channels_ = {
100+ 'mlapdv' : np .c_ [channels ['x' ], channels ['y' ], channels ['z' ]] * 1e6 ,
101+ 'brainLocationIds_ccf_2017' : channels ['atlas_id' ],
102+ 'localCoordinates' : np .c_ [channels ['lateral_um' ], channels ['axial_um' ]]}
103+ return channels_
104+
105+
98106def _channels_alf2bunch (channels , brain_regions = None ):
99107 # reformat the dictionary according to the standard that comes out of Alyx
100108 channels_ = {
101109 'x' : channels ['mlapdv' ][:, 0 ].astype (np .float64 ) / 1e6 ,
102110 'y' : channels ['mlapdv' ][:, 1 ].astype (np .float64 ) / 1e6 ,
103111 'z' : channels ['mlapdv' ][:, 2 ].astype (np .float64 ) / 1e6 ,
104112 'acronym' : None ,
105- 'atlas_id' : channels ['brainLocationIds_ccf_2017' ]
113+ 'atlas_id' : channels ['brainLocationIds_ccf_2017' ],
114+ 'axial_um' : channels ['localCoordinates' ][:, 1 ],
115+ 'lateral_um' : channels ['localCoordinates' ][:, 0 ],
106116 }
107117 if brain_regions :
108118 channels_ ['acronym' ] = brain_regions .get (channels_ ['atlas_id' ])['acronym' ]
@@ -207,24 +217,33 @@ def _load_channels_locations_from_disk(eid, collection=None, one=None, revision=
207217 channels_aligned = one .load_object (eid , 'channels' , collection = ac_collection )
208218 channels [probe ] = channel_locations_interpolation (channels_aligned , channels [probe ])
209219 # only have to reformat channels if we were able to load coordinates from disk
210- channels [probe ] = _channels_alf2bunch (channels [probe ], brain_regions = brain_regions )
220+ channels [probe ] = _channels_alf2bunch (channels [probe ], brain_regions = brain_regions )
211221 return channels
212222
213223
214- def channel_locations_interpolation (channels_aligned , channels ):
224+ def channel_locations_interpolation (channels_aligned , channels , brain_regions = None ):
215225 """
216226 oftentimes the channel map for different spike sorters may be different so interpolate the alignment onto
217227 if there is no spike sorting in the base folder, the alignment doesn't have the localCoordinates field
218228 so we reconstruct from the Neuropixel map. This only happens for early pykilosort sorts
219229 :param channels_aligned: Bunch or dictionary of aligned channels containing at least keys
220- 'mlapdv' and 'brainLocationIds_ccf_2017' - those are the guide for the interpolation
230+ 'localCoordinates', 'mlapdv' and 'brainLocationIds_ccf_2017'
231+ OR
232+ 'x', 'y', 'z', 'acronym', 'axial_um'
233+ those are the guide for the interpolation
221234 :param channels: Bunch or dictionary of aligned channels containing at least keys 'localCoordinates'
222- :return: Bunch or dictionary of channels with extra keys 'mlapdv' and 'brainLocationIds_ccf_2017'
235+ :param brain_regions: None (default) or ibllib.atlas.BrainRegions object
236+ if None will return a dict with keys 'localCoordinates', 'mlapdv', 'brainLocationIds_ccf_2017
237+ if a brain region object is provided, outputts a dict with keys
238+ 'x', 'y', 'z', 'acronym', 'atlas_id', 'axial_um', 'lateral_um'
239+ :return: Bunch or dictionary of channels with brain coordinates keys
223240 """
224241 nch = channels ['localCoordinates' ].shape [0 ]
242+ if set (['x' , 'y' , 'z' ]).issubset (set (channels_aligned .keys ())):
243+ channels_aligned = _channels_bunch2alf (channels_aligned )
225244 if 'localCoordinates' in channels_aligned .keys ():
226245 aligned_depths = channels_aligned ['localCoordinates' ][:, 1 ]
227- else :
246+ else : # this is a edge case for a few spike sorting sessions
228247 assert channels_aligned ['mlapdv' ].shape [0 ] == 384
229248 NEUROPIXEL_VERSION = 1
230249 from ibllib .ephys .neuropixel import trace_header
@@ -238,7 +257,10 @@ def channel_locations_interpolation(channels_aligned, channels):
238257 # the brain locations have to be interpolated by nearest neighbour
239258 fcn_interp = interp1d (depth_aligned , channels_aligned ['brainLocationIds_ccf_2017' ][ind_aligned ], kind = 'nearest' )
240259 channels ['brainLocationIds_ccf_2017' ] = fcn_interp (depths )[iinv ].astype (np .int32 )
241- return channels
260+ if brain_regions is not None :
261+ return _channels_alf2bunch (channels , brain_regions = brain_regions )
262+ else :
263+ return channels
242264
243265
244266def _load_channel_locations_traj (eid , probe = None , one = None , revision = None , aligned = False ,
@@ -531,7 +553,7 @@ def merge_clusters_channels(dic_clus, channels, keys_to_add_extra=None):
531553 dic_clus : dict of one.alf.io.AlfBunch
532554 1 bunch per probe, containing cluster information
533555 channels : dict of one.alf.io.AlfBunch
534- 1 bunch per probe, containing channels bunch with keys ('acronym', 'atlas_id')
556+ 1 bunch per probe, containing channels bunch with keys ('acronym', 'atlas_id', 'x', 'y', z', 'localCoordinates' )
535557 keys_to_add_extra : list of str
536558 Any extra keys to load into channels bunches
537559
@@ -541,7 +563,7 @@ def merge_clusters_channels(dic_clus, channels, keys_to_add_extra=None):
541563 clusters (1 bunch per probe) with new keys values.
542564 """
543565 probe_labels = list (channels .keys ()) # Convert dict_keys into list
544- keys_to_add_default = ['acronym' , 'atlas_id' , 'x' , 'y' , 'z' ]
566+ keys_to_add_default = ['acronym' , 'atlas_id' , 'x' , 'y' , 'z' , 'axial_um' , 'lateral_um' ]
545567
546568 if keys_to_add_extra is None :
547569 keys_to_add = keys_to_add_default
@@ -550,10 +572,9 @@ def merge_clusters_channels(dic_clus, channels, keys_to_add_extra=None):
550572 keys_to_add = list (set (keys_to_add_extra + keys_to_add_default ))
551573
552574 for label in probe_labels :
553- try :
554- clu_ch = dic_clus [label ]['channels' ]
555-
556- for key in keys_to_add :
575+ clu_ch = dic_clus [label ]['channels' ]
576+ for key in keys_to_add :
577+ try :
557578 assert key in channels [label ].keys () # Check key is in channels
558579 ch_key = channels [label ][key ]
559580 nch_key = len (ch_key ) if ch_key is not None else 0
@@ -564,11 +585,9 @@ def merge_clusters_channels(dic_clus, channels, keys_to_add_extra=None):
564585 f'Probe { label } : merging channels and clusters for key "{ key } " has { nch_key } on channels'
565586 f' but expected { max (clu_ch )} . Data in new cluster key "{ key } " is returned empty.' )
566587 dic_clus [label ][key ] = []
567- except AssertionError :
568- _logger .warning (
569- f'Either clusters or channels does not have key { label } , could not'
570- f' merge' )
571- continue
588+ except AssertionError :
589+ _logger .warning (f'Either clusters or channels does not have key { key } , could not merge' )
590+ continue
572591
573592 return dic_clus
574593
0 commit comments