Add read_nwb_sorting_analyzer: build a SortingAnalyzer from an NWB Units table#4645
Add read_nwb_sorting_analyzer: build a SortingAnalyzer from an NWB Units table#4645h-mayorquin wants to merge 44 commits into
Conversation
…load_analyzer_from_nwb
…erface into load_analyzer_from_nwb
# Conflicts: # src/spikeinterface/extractors/nwbextractors.py
for more information, see https://pre-commit.ci
…eberto' into load_analyzer_nwb_heberto
|
This is failing on |
…ikeinterface into load_analyzer_nwb_heberto
Fixed in last couple of commits |
# Conflicts: # src/spikeinterface/extractors/nwbextractors.py
|
Thanks for fixing the multi-group bug and the random-spikes handling. I built on that and fixed a few more things on the branch:
Two behavior changes to flag: with a |
read_nwb_sorting_analyzerbuilds a curatableSortingAnalyzerdirectly from an NWB (Neurodata Without Borders) Units table, populating each extension from what the file already stores rather than recomputing it. When the Units table haswaveform_mean, the analyzer is built recordingless from those stored templates, plus the per-unit metrics and theelectrodesregion for sparsity; when the file has an accessible ElectricalSeries, it is used as the recording. It mirrorsread_kilosort_as_analyzerin structure, injecting the templates, quality and template metrics, sparsity, and random_spikes extensions from the file's contents. This supersedes the earlier draft #4270.The reads are deliberate: Units columns are classified from metadata and only the templates, the
electrodesregion, and the scalar metric/label columns are materialized, while the large per-spike ragged columns (spike times, amplitudes, depths) are never touched at build. The sorting is kept lazy so its spike times are read only on demand, which builds on #4662 (single bulk-read NWB spike vector) and thecopy_sortingoption (#4668); the recordingless case builds a lightweight placeholder recording from the electroderel_x/rel_ygeometry (viagenerate_ground_truth_recording, #4588) purely to carry probe geometry into the standard constructor, then drops it. Together these keep the build small and memory-light regardless of file size.Because the reads are deliberate and the sorting stays lazy, the function works the same whether the file is local or streamed (
stream_modeis passed through to the extractors). That makes the streamed case cheap: as a check, building from a real IBL (International Brain Laboratory) processed file on dandiset 000409, session6713a4a7-faed-4df2-acab-ee4e63326f8d(898 units, 20.7M spikes), produced a curatable analyzer in about 14 s while transferring only ~22 MB, with the ~130 MB spike read deferred until a spike-based view needs it. This PR is the reader itself; a separate how-to PR will cover the streaming-from-DANDI workflow in depth. It depends on #4662 and thecopy_sortingPR (#4668), which should merge first so this branch rebases down to just the reader.