Skip to content

Commit 45fb84f

Browse files
authored
Merge pull request #19 from dj-sciops/fix/curation-channel-mapping
Fix KeyError in ApplyOfficialCuration.make for multi-insertion probes
2 parents 1dd8679 + 8f46414 commit 45fb84f

1 file changed

Lines changed: 38 additions & 3 deletions

File tree

element_array_ephys/spike_sorting/ephys_curation.py

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)