@@ -406,12 +406,47 @@ def make(self, key):
406406 new_si_unit_reverse_map = {v : k for k , v in new_si_unit_map .items ()}
407407
408408 # Get channel and electrode-site mapping
409+ # For SI-processed data, Kilosort's spike_sites contains device_channel_indices
410+ # (sequential 0, 1, 2...) which may differ from the original channel_idx in
411+ # EphysRecording.Channel (e.g., 32-63 for multi-insertion probes like MBA).
412+ # Use the sorting_analyzer's probe to correctly map channel indices to electrodes.
409413 electrode_query = (ephys .EphysRecording .Channel & clus_key ).proj (
410414 ..., "-channel_name"
411415 )
412- channel2electrode_map : dict [int , dict ] = {
413- chn .pop ("channel_idx" ): chn for chn in electrode_query .fetch (as_dict = True )
414- }
416+
417+ # Get sorting_analyzer to access the probe's channel mapping
418+ clustering_method , output_dir = (
419+ ephys .ClusteringTask * ephys .ClusteringParamSet & clus_key
420+ ).fetch1 ("clustering_method" , "clustering_output_dir" )
421+ output_dir = find_full_path (ephys .get_ephys_root_data_dir (), output_dir )
422+ sorter_name = clustering_method .replace ("." , "_" )
423+ si_sorting_analyzer_dir = output_dir / sorter_name / "sorting_analyzer"
424+
425+ # If sorting_analyzer not available locally, fetch from external storage (S3)
426+ if not si_sorting_analyzer_dir .exists ():
427+ _ = (ephys_sorter .PostProcessing .File & clus_key ).fetch ("file" )
428+
429+ if si_sorting_analyzer_dir .exists ():
430+ import spikeinterface as si
431+
432+ sorting_analyzer = si .load_sorting_analyzer (folder = si_sorting_analyzer_dir )
433+ # Create electrode_map keyed by electrode ID
434+ electrode_map : dict [int , dict ] = {
435+ elec ["electrode" ]: elec for elec in electrode_query .fetch (as_dict = True )
436+ }
437+ # Map device_channel_indices to electrode info using probe's contact_ids
438+ channel2electrode_map : dict [int , dict ] = {
439+ chn_idx : electrode_map [int (elec_id )]
440+ for chn_idx , elec_id in zip (
441+ sorting_analyzer .get_probe ().device_channel_indices ,
442+ sorting_analyzer .get_probe ().contact_ids ,
443+ )
444+ }
445+ else :
446+ # Fallback for non-SI processed data - use original channel_idx
447+ channel2electrode_map : dict [int , dict ] = {
448+ chn ["channel_idx" ]: chn for chn in electrode_query .fetch (as_dict = True )
449+ }
415450
416451 sample_rate = kilosort_dataset .data ["params" ]["sample_rate" ]
417452 spike_times = kilosort_dataset .data ["spike_times" ]
0 commit comments