Skip to content

Commit 6f0ed09

Browse files
m-beaualejoe91pre-commit-ci[bot]chrishalcrowsamuelgarcia
authored
Valid unit periods extension (#4299)
Co-authored-by: Alessio Buccino <alejoe9187@gmail.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Chris Halcrow <57948917+chrishalcrow@users.noreply.github.com> Co-authored-by: Samuel Garcia <sam.garcia.die@gmail.com>
1 parent 456265c commit 6f0ed09

24 files changed

Lines changed: 1605 additions & 107 deletions

doc/index.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ SpikeInterface is made of several modules to deal with different aspects of the
3030
- visualize recordings and spike sorting outputs in several ways (matplotlib, sortingview, jupyter, ephyviewer)
3131
- export a report and/or export to phy
3232
- curate your sorting with several strategies (ml-based, metrics based, manual, ...)
33-
- offer a powerful Qt-based or we-based viewer in a separate package `spikeinterface-gui <https://github.com/SpikeInterface/spikeinterface-gui>`_ for manual curation that replace phy.
33+
- offer a powerful desktop or web viewer in a separate package `spikeinterface-gui <https://github.com/SpikeInterface/spikeinterface-gui>`_ for manual curation that replace phy.
3434
- have powerful sorting components to build your own sorter.
3535
- have a full motion/drift correction framework (See :ref:`motion_correction`)
3636

doc/modules/core.rst

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -93,10 +93,11 @@ with 16 channels:
9393
timestamps = np.arange(num_samples) / sampling_frequency + 300
9494
recording.set_times(times=timestamps, segment_index=0)
9595
96-
**Note**:
97-
Raw data formats often store data as integer values for memory efficiency. To give these integers meaningful physical units (uV), you can apply a gain and an offset.
98-
Many devices have their own gains and offsets necessary to convert their data and these values are handled by SpikeInterface for its extractors. This
99-
is triggered by the :code:`return_in_uV` parameter in :code:`get_traces()`, (see above example), which will return the traces in uV. Read more in our how to guide, :ref:`physical_units`.
96+
.. note::
97+
98+
Raw data formats often store data as integer values for memory efficiency. To give these integers meaningful physical units (uV), you can apply a gain and an offset.
99+
Many devices have their own gains and offsets necessary to convert their data and these values are handled by SpikeInterface for its extractors. This
100+
is triggered by the :code:`return_in_uV` parameter in :code:`get_traces()`, (see above example), which will return the traces in uV. Read more in our how to guide, :ref:`physical_units`.
100101

101102

102103
Sorting
@@ -180,8 +181,9 @@ a numpy.array with dtype `[("sample_index", "int64"), ("unit_index", "int64"), (
180181
For computations which are done unit-by-unit, like computing isi-violations per unit, it is better that
181182
spikes from a single unit are concurrent in memory. For these other cases, we can re-order the
182183
`spike_vector` in different ways:
183-
* order by unit, then segment, then sample
184-
* order by segment, then unit, then sample
184+
185+
* order by unit, then segment, then sample
186+
* order by segment, then unit, then sample
185187

186188
This is done using `sorting.to_reordered_spike_vector()`. The first time a reordering is done, the
187189
reordered spiketrain is cached in memory by default. Users should rarely have to worry about these
@@ -458,9 +460,11 @@ It represents unsorted waveform cutouts. Some acquisition systems, in fact, allo
458460
threshold and only record the times at which a peak was detected and the waveform cut out around
459461
the peak.
460462

461-
**NOTE**: while we support this class (mainly for legacy formats), this approach is a bad practice
462-
and is highly discouraged! Most modern spike sorters, in fact, require the raw traces to perform
463-
template matching to recover spikes!
463+
.. note::
464+
465+
While we support this class (mainly for legacy formats), this approach is a bad practice
466+
and is highly discouraged! Most modern spike sorters, in fact, require the raw traces to perform
467+
template matching to recover spikes!
464468

465469
Here we assume :code:`snippets` is a :py:class:`~spikeinterface.core.BaseSnippets` object
466470
with 16 channels:
@@ -548,9 +552,11 @@ Sparsity is defined as the subset of channels on which waveforms (and related in
548552
sparsity is not global, but it is unit-specific. Importantly, saving sparse waveforms, especially for high-density probes,
549553
dramatically reduces the size of the waveforms extension if computed.
550554

551-
**NOTE** As of :code:`0.101.0` all :code:`SortingAnalyzer`'s have a default of :code:`sparse=True`. This was first
552-
introduced in :code:`0.99.0` for :code:`WaveformExtractor`'s and will be the default going forward. To obtain dense
553-
waveforms you will need to set :code:`sparse=False` at the creation of the :code:`SortingAnalyzer`.
555+
.. note::
556+
557+
As of :code:`0.101.0` all :code:`SortingAnalyzer`'s have a default of :code:`sparse=True`. This was first
558+
introduced in :code:`0.99.0` for :code:`WaveformExtractor`'s and will be the default going forward. To obtain dense
559+
waveforms you will need to set :code:`sparse=False` at the creation of the :code:`SortingAnalyzer`.
554560

555561

556562
Sparsity can be computed from a :py:class:`~spikeinterface.core.SortingAnalyzer` object with the
@@ -854,10 +860,12 @@ The same functions are also available for
854860
:py:func:`~spikeinterface.core.select_segment_sorting`).
855861

856862

857-
**Note** :py:func:`~spikeinterface.core.append_recordings` and:py:func:`~spikeinterface.core.concatenate_recordings`
858-
have the same goal, aggregate recording pieces on the time axis but with 2 different strategies! One is keeping the
859-
multi segments concept, the other one is breaking it!
860-
See this example for more detail :ref:`example_segments`.
863+
.. note::
864+
865+
:py:func:`~spikeinterface.core.append_recordings` and:py:func:`~spikeinterface.core.concatenate_recordings`
866+
have the same goal, aggregate recording pieces on the time axis but with 2 different strategies! One is keeping the
867+
multi segments concept, the other one is breaking it!
868+
See this example for more detail :ref:`example_segments`.
861869

862870

863871

doc/modules/exporters.rst

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,11 @@ and behavioral data. It can be used to decode behavior, make tuning curves, comp
1212
The :py:func:`~spikeinterface.exporters.to_pynapple_tsgroup` function allows you to convert a
1313
SortingAnalyzer to Pynapple's ``TsGroup`` object on the fly.
1414

15-
**Note** : When creating the ``TsGroup``, we will use the underlying time support of the SortingAnalyzer.
16-
How this works depends on your acquisition system. You can use the ``get_times`` method on a recording
17-
(``my_recording.get_times()``) to find the time support of your recording.
15+
.. note::
16+
17+
When creating the ``TsGroup``, we will use the underlying time support of the SortingAnalyzer.
18+
How this works depends on your acquisition system. You can use the ``get_times`` method on a recording
19+
(``my_recording.get_times()``) to find the time support of your recording.
1820

1921
When constructed, if ``attach_unit_metadata`` is set to ``True``, any relevant unit information
2022
is propagated to the ``TsGroup``. The ``to_pynapple_tsgroup`` checks if unit locations, quality
@@ -54,13 +56,15 @@ The :py:func:`~spikeinterface.exporters.export_to_phy` function allows you to us
5456
`Phy template GUI <https://github.com/cortex-lab/phy>`_ for visual inspection and manual curation of spike sorting
5557
results.
5658

57-
**Note** : :py:func:`~spikeinterface.exporters.export_to_phy` speed and the size of the folder will highly depend
58-
on the sparsity of the :code:`SortingAnalyzer` itself or the external specified sparsity.
59-
The Phy viewer enables one to explore PCA projections, spike amplitudes, waveforms and quality of spike sorting results.
60-
So if these pieces of information have already been computed as extensions (see :ref:`modules/postprocessing:Extensions as AnalyzerExtensions`),
61-
then exporting to Phy should be fast (and the user has better control of the parameters for the extensions).
62-
If not pre-computed, then the required extensions (e.g., :code:`spike_amplitudes`, :code:`principal_components`)
63-
can be computed directly at export time.
59+
.. note::
60+
61+
:py:func:`~spikeinterface.exporters.export_to_phy` speed and the size of the folder will highly depend
62+
on the sparsity of the :code:`SortingAnalyzer` itself or the external specified sparsity.
63+
The Phy viewer enables one to explore PCA projections, spike amplitudes, waveforms and quality of spike sorting results.
64+
So if these pieces of information have already been computed as extensions (see :ref:`modules/postprocessing:Extensions as AnalyzerExtensions`),
65+
then exporting to Phy should be fast (and the user has better control of the parameters for the extensions).
66+
If not pre-computed, then the required extensions (e.g., :code:`spike_amplitudes`, :code:`principal_components`)
67+
can be computed directly at export time.
6468

6569
The input of the :py:func:`~spikeinterface.exporters.export_to_phy` is a :code:`SortingAnalyzer` object.
6670

@@ -131,12 +135,14 @@ The report includes summary figures of the spike sorting output (e.g. amplitude
131135
depth VS amplitude) as well as unit-specific reports, that include waveforms, templates, template maps,
132136
ISI distributions, and more.
133137

134-
**Note** : similarly to :py:func:`~spikeinterface.exporters.export_to_phy` the
135-
:py:func:`~spikeinterface.exporters.export_report` depends on the sparsity of the :code:`SortingAnalyzer` itself and
136-
on which extensions have been computed. For example, :code:`spike_amplitudes` and :code:`correlograms` related plots
137-
will be automatically included in the report if the associated extensions are computed in advance.
138-
The function can perform these computations as well, but it is a better practice to compute everything that's needed
139-
beforehand.
138+
.. note::
139+
140+
Similarly to :py:func:`~spikeinterface.exporters.export_to_phy` the
141+
:py:func:`~spikeinterface.exporters.export_report` depends on the sparsity of the :code:`SortingAnalyzer` itself and
142+
on which extensions have been computed. For example, :code:`spike_amplitudes` and :code:`correlograms` related plots
143+
will be automatically included in the report if the associated extensions are computed in advance.
144+
The function can perform these computations as well, but it is a better practice to compute everything that's needed
145+
beforehand.
140146

141147
Note that every unit will generate a summary unit figure, so the export process can be slow for spike sorting outputs
142148
with many units!

doc/modules/postprocessing.rst

Lines changed: 48 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -163,8 +163,10 @@ Extensions are generally saved in two ways, suitable for two workflows:
163163
:code:`sorting_analyzer.compute('waveforms', save=False)`).
164164

165165

166-
**NOTE**: We recommend choosing a workflow and sticking with it. Either keep everything on disk or keep everything in memory until
167-
you'd like to save. A mixture can lead to unexpected behavior. For example, consider the following code
166+
.. note::
167+
168+
We recommend choosing a workflow and sticking with it. Either keep everything on disk or keep everything in memory until
169+
you'd like to save. A mixture can lead to unexpected behavior. For example, consider the following code
168170

169171
.. code::
170172
@@ -257,15 +259,35 @@ spike_amplitudes
257259
This extension computes the amplitude of each spike as the value of the traces on the extremum channel at the times of
258260
each spike. The extremum channel is computed from the templates.
259261

262+
260263
**NOTE:** computing spike amplitudes is highly recommended before calculating amplitude-based quality metrics, such as
261264
:ref:`amp_cutoff` and :ref:`amp_median`.
262265

263266
.. code-block:: python
264267
265-
amplitudes = sorting_analyzer.compute(input="spike_amplitudes", peak_sign="neg")
268+
amplitudes = sorting_analyzer.compute(input="spike_amplitudes")
266269
267270
For more information, see :py:func:`~spikeinterface.postprocessing.compute_spike_amplitudes`
268271

272+
273+
.. _postprocessing_amplitude_scalings:
274+
275+
amplitude_scalings
276+
^^^^^^^^^^^^^^^^^^
277+
278+
This extension computes the amplitude scaling of each spike as the value of the linear fit between the template and the
279+
spike waveform. In case of spatio-temporal collisions, a multi-linear fit is performed using the templates of all units
280+
involved in the collision.
281+
282+
**NOTE:** computing amplitude scalings is highly recommended before calculating amplitude-based quality metrics, such as
283+
:ref:`amp_cutoff` and :ref:`amp_median`.
284+
285+
.. code-block:: python
286+
287+
amplitude_scalings = sorting_analyzer.compute(input="amplitude_scalings")
288+
289+
For more information, see :py:func:`~spikeinterface.postprocessing.compute_amplitude_scalings`
290+
269291
.. _postprocessing_spike_locations:
270292

271293
spike_locations
@@ -367,7 +389,29 @@ This extension computes the histograms of inter-spike-intervals. The computed ou
367389
method="auto"
368390
)
369391
370-
For more information, see :py:func:`~spikeinterface.postprocessing.compute_isi_histograms`
392+
valid_unit_periods
393+
^^^^^^^^^^^^^^^^^^
394+
395+
This extension computes the valid unit periods for each unit based on the estimation of false positive rates
396+
(using RP violation - see ::doc:`metrics/qualitymetrics/isi_violations`) and false negative rates
397+
(using amplitude cutoff - see ::doc:`metrics/qualitymetrics/amplitude_cutoff`) computed over chunks of the recording.
398+
The valid unit periods are the periods where both false positive and false negative rates are below specified
399+
thresholds. Periods can be either absolute (in seconds), same for all units, or relative, where
400+
chunks will be unit-specific depending on firing rate (with a target number of spikes per chunk).
401+
402+
.. code-block:: python
403+
404+
valid_periods = sorting_analyzer.compute(
405+
input="valid_unit_periods",
406+
period_mode='relative',
407+
target_num_spikes=300,
408+
fp_threshold=0.1,
409+
fn_threshold=0.1,
410+
)
411+
412+
For more information, see :py:func:`~spikeinterface.postprocessing.compute_valid_unit_periods`.
413+
414+
371415

372416

373417
Other postprocessing tools

doc/modules/sortingcomponents.rst

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,9 @@ Other variants are also implemented (but less tested or not so useful):
8181
* **'by_channel_torch'** (requires :code:`torch`): pytorch implementation (GPU-compatible) that uses max pooling for time deduplication
8282
* **'locally_exclusive_torch'** (requires :code:`torch`): pytorch implementation (GPU-compatible) that uses max pooling for space-time deduplication
8383

84-
**NOTE**: the torch implementations give slightly different results due to a different implementation.
84+
.. note::
85+
86+
The torch implementations give slightly different results due to a different implementation.
8587

8688
Peak detection, as many of the other sorting components, can be run in parallel.
8789

@@ -274,7 +276,7 @@ handle drift can benefit from drift estimation/correction.
274276
Especially for acute Neuropixels-like probes, this is a crucial step.
275277

276278
The motion estimation step comes after peak detection and peak localization. Read more about
277-
it in the :ref:`_motion_correction` modules doc, and a more practical guide in the
279+
it in the :ref:`motion_correction` modules doc, and a more practical guide in the
278280
:ref:`handle-drift-in-your-recording` How To.
279281

280282
Here is an example with non-rigid motion estimation:

doc/references.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,8 @@ References
118118
119119
.. [Diggelmann] `Automatic spike sorting for high-density microelectrode arrays. 2018. <https://pubmed.ncbi.nlm.nih.gov/30207864/>`_
120120
121+
.. [Fabre] `Bombcell: automated curation and cell classification of spike-sorted electrophysiology data. 2023. <https://doi.org/10.5281/zenodo.8172822>`
122+
121123
.. [Garcia2024] `A Modular Implementation to Handle and Benchmark Drift Correction for High-Density Extracellular Recordings. 2024. <https://pubmed.ncbi.nlm.nih.gov/38238082/>`_
122124
123125
.. [Garcia2022] `How Do Spike Collisions Affect Spike Sorting Performance? <https://doi.org/10.1523/ENEURO.0105-22.2022>`_

0 commit comments

Comments
 (0)