Skip to content

Commit 9b28521

Browse files
authored
Merge branch 'main' into kilosort_matching_gpl
2 parents dfcdc7c + 12a1276 commit 9b28521

172 files changed

Lines changed: 7079 additions & 1613 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 12 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,20 @@
11
name: Install packages
22
description: This action installs the package and its dependencies for testing
33

4-
inputs:
5-
python-version:
6-
description: 'Python version to set up'
7-
required: false
8-
os:
9-
description: 'Operating system to set up'
10-
required: false
11-
124
runs:
135
using: "composite"
146
steps:
157
- name: Install dependencies
168
run: |
17-
sudo apt install git
189
git config --global user.email "CI@example.com"
1910
git config --global user.name "CI Almighty"
20-
python -m venv ${{ github.workspace }}/test_env # Environment used in the caching step
21-
python -m pip install -U pip # Official recommended way
22-
source ${{ github.workspace }}/test_env/bin/activate
2311
pip install tabulate # This produces summaries at the end
2412
pip install -e .[test,extractors,streaming_extractors,test_extractors,full]
2513
shell: bash
26-
- name: Force installation of latest dev from key-packages when running dev (not release)
27-
run: |
28-
source ${{ github.workspace }}/test_env/bin/activate
29-
spikeinterface_is_dev_version=$(python -c "import spikeinterface; print(spikeinterface.DEV_MODE)")
30-
if [ $spikeinterface_is_dev_version = "True" ]; then
31-
echo "Running spikeinterface dev version"
32-
pip install --no-cache-dir git+https://github.com/NeuralEnsemble/python-neo
33-
pip install --no-cache-dir git+https://github.com/SpikeInterface/probeinterface
34-
fi
35-
echo "Running tests for release, using pyproject.toml versions of neo and probeinterface"
14+
- name: Install git-annex
3615
shell: bash
37-
- name: git-annex install
3816
run: |
17+
pip install datalad-installer
3918
wget https://downloads.kitenet.net/git-annex/linux/current/git-annex-standalone-amd64.tar.gz
4019
mkdir /home/runner/work/installation
4120
mv git-annex-standalone-amd64.tar.gz /home/runner/work/installation/
@@ -44,4 +23,14 @@ runs:
4423
tar xvzf git-annex-standalone-amd64.tar.gz
4524
echo "$(pwd)/git-annex.linux" >> $GITHUB_PATH
4625
cd $workdir
26+
git config --global filter.annex.process "git-annex filter-process" # recommended for efficiency
27+
- name: Force installation of latest dev from key-packages when running dev (not release)
28+
run: |
29+
spikeinterface_is_dev_version=$(python -c "import spikeinterface; print(spikeinterface.DEV_MODE)")
30+
if [ $spikeinterface_is_dev_version = "True" ]; then
31+
echo "Running spikeinterface dev version"
32+
pip install --no-cache-dir git+https://github.com/NeuralEnsemble/python-neo
33+
pip install --no-cache-dir git+https://github.com/SpikeInterface/probeinterface
34+
fi
35+
echo "Running tests for release, using pyproject.toml versions of neo and probeinterface"
4736
shell: bash

.github/workflows/all-tests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ jobs:
4747
echo "$file was changed"
4848
done
4949
50-
- name: Set testing environment # This decides which tests are run and whether to install especial dependencies
50+
- name: Set testing environment # This decides which tests are run and whether to install special dependencies
5151
shell: bash
5252
run: |
5353
changed_files="${{ steps.changed-files.outputs.all_changed_files }}"

.github/workflows/full-test-with-codecov.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ jobs:
2323
- uses: actions/checkout@v4
2424
- uses: actions/setup-python@v5
2525
with:
26-
python-version: '3.10'
26+
python-version: '3.12'
2727
- name: Get ephy_testing_data current head hash
2828
# the key depends on the last comit repo https://gin.g-node.org/NeuralEnsemble/ephy_testing_data.git
2929
id: vars
@@ -45,7 +45,6 @@ jobs:
4545
env:
4646
HDF5_PLUGIN_PATH: ${{ github.workspace }}/hdf5_plugin_path_maxwell
4747
run: |
48-
source ${{ github.workspace }}/test_env/bin/activate
4948
pytest -m "not sorters_external" --cov=./ --cov-report xml:./coverage.xml -vv -ra --durations=0 | tee report_full.txt; test ${PIPESTATUS[0]} -eq 0 || exit 1
5049
echo "# Timing profile of full tests" >> $GITHUB_STEP_SUMMARY
5150
python ./.github/scripts/build_job_summary.py report_full.txt >> $GITHUB_STEP_SUMMARY

doc/api.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,9 @@ spikeinterface.curation
346346
.. autofunction:: remove_redundant_units
347347
.. autofunction:: remove_duplicated_spikes
348348
.. autofunction:: remove_excess_spikes
349+
.. autofunction:: load_model
350+
.. autofunction:: auto_label_units
351+
.. autofunction:: train_model
349352

350353
Deprecated
351354
~~~~~~~~~~

doc/conf.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,12 +119,15 @@
119119

120120
# for sphinx gallery plugin
121121
sphinx_gallery_conf = {
122-
'only_warn_on_example_error': True,
122+
# This is the default but including here explicitly. Should build all docs and fail on gallery failures only.
123+
# other option would be abort_on_example_error, but this fails on first failure. So we decided against this.
124+
'only_warn_on_example_error': False,
123125
'examples_dirs': ['../examples/tutorials'],
124126
'gallery_dirs': ['tutorials' ], # path where to save gallery generated examples
125127
'subsection_order': ExplicitOrder([
126128
'../examples/tutorials/core',
127129
'../examples/tutorials/extractors',
130+
'../examples/tutorials/curation',
128131
'../examples/tutorials/qualitymetrics',
129132
'../examples/tutorials/comparison',
130133
'../examples/tutorials/widgets',

doc/development/development.rst

Lines changed: 38 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ for the :code:`spikeinterface.extractors` module, you can use the following comm
6161
6262
The markers are located in the :code:`pyproject.toml` file in the root of the repository.
6363

64-
Note that you should install the package before running the tests. You can do this by running the following command:
64+
Note that you should install spikeinterface before running the tests. You can do this by running the following command:
6565

6666
.. code-block:: bash
6767
@@ -72,7 +72,7 @@ You can change the :code:`[test,extractors,full]` to install only the dependenci
7272
The specific environment for the CI is specified in the :code:`.github/actions/build-test-environment/action.yml` and you can
7373
find the full tests in the :code:`.github/workflows/full_test.yml` file.
7474

75-
The extractor tests require datalad for some of the tests. Here are instructions for installing datalad:
75+
Some of the extractor tests require datalad. Here are instructions for installing datalad:
7676

7777
Installing Datalad
7878
------------------
@@ -87,13 +87,13 @@ Stylistic conventions
8787

8888
SpikeInterface maintains a consistent coding style across the project. This helps to ensure readability and
8989
maintainability of the code, making it easier for contributors to collaborate. To facilitate code style
90-
for the developer we use the follwing tools and conventions:
90+
for the developer we use the following tools and conventions:
9191

9292

9393
Install Black and pre-commit
9494
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
9595

96-
We use the python formatter Black, with defaults set in the :code:`pyproject.toml`. This allows for
96+
We use the Python formatter Black, with defaults set in the :code:`pyproject.toml`. This allows for
9797
easy local formatting of code.
9898

9999
To install Black, you can use pip, the Python package installer. Run the following command in your terminal:
@@ -213,6 +213,25 @@ We use Sphinx to build the documentation. To build the documentation locally, yo
213213
214214
This will build the documentation in the :code:`doc/_build/html` folder. You can open the :code:`index.html` file in your browser to see the documentation.
215215

216+
Adding new documentation
217+
------------------------
218+
219+
Documentation can be added as a
220+
`sphinx-gallery <https://sphinx-gallery.github.io/stable/index.html>`_
221+
Python file ('tutorials')
222+
or a
223+
`sphinx rst <https://sphinx-tutorial.readthedocs.io/step-1/>`_
224+
file (all other sections).
225+
226+
To add a new tutorial, add your ``.py`` file to ``spikeinterface/examples``.
227+
Then, update the ``spikeinterface/doc/tutorials_custom_index.rst`` file
228+
to make a new card linking to the page and an optional image. See
229+
``tutorials_custom_index.rst`` header for more information.
230+
231+
For other sections, write your documentation in ``.rst`` format and add
232+
the page to the appropriate ``index.rst`` file found in the relevant
233+
folder (e.g. ``how_to/index.rst``).
234+
216235
How to run code coverage locally
217236
--------------------------------
218237
To run code coverage locally, you can use the following command:
@@ -223,7 +242,7 @@ To run code coverage locally, you can use the following command:
223242
224243
This will run the tests and generate a report in the :code:`htmlcov` folder. You can open the :code:`index.html` file in your browser to see the report.
225244

226-
Note, however, that the running time of the command above will be slow. If you want to run the tests for a specific module, you can use the following command:
245+
Note, however, that the running time of the command above will be quite long. If you want to run the tests for a specific module, you can use the following command:
227246

228247
.. code-block:: bash
229248
@@ -233,21 +252,21 @@ Implement a new extractor
233252
-------------------------
234253

235254
SpikeInterface already supports over 30 file formats, but the acquisition system you use might not be among the
236-
supported formats list (***ref***). Most of the extractors rely on the `NEO <https://github.com/NeuralEnsemble/python-neo>`_
255+
supported formats list (****ref****). Most of the extractors rely on the `NEO <https://github.com/NeuralEnsemble/python-neo>`_
237256
package to read information from files.
238257
Therefore, to implement a new extractor to handle the unsupported format, we recommend making a new :code:`neo.rawio.BaseRawIO` class (see `example <https://github.com/NeuralEnsemble/python-neo/blob/master/neo/rawio/examplerawio.py#L44>`_).
239258
Once that is done, the new class can be easily wrapped into SpikeInterface as an extension of the
240259
:py:class:`~spikeinterface.extractors.neoextractors.neobaseextractors.NeoBaseRecordingExtractor`
241260
(for :py:class:`~spikeinterface.core.BaseRecording` objects) or
242261
:py:class:`~spikeinterface.extractors.neoextractors.neobaseextractors.NeoBaseRecordingExtractor`
243262
(for :py:class:`~spikeinterface.core.BaseSorting` objects) or with a few lines of
244-
code (e.g., see reader for `SpikeGLX <https://github.com/SpikeInterface/spikeinterface/blob/0.96.1/spikeinterface/extractors/neoextractors/spikeglx.py>`_
245-
or `Neuralynx <https://github.com/SpikeInterface/spikeinterface/blob/0.96.1/spikeinterface/extractors/neoextractors/neuralynx.py>`_).
263+
code (e.g., see reader for `SpikeGLX <https://github.com/SpikeInterface/spikeinterface/blob/main/src/spikeinterface/extractors/neoextractors/spikeglx.py>`_
264+
or `Neuralynx <https://github.com/SpikeInterface/spikeinterface/blob/main/src/spikeinterface/extractors/neoextractors/neuralynx.py>`_).
246265

247-
**NOTE:** implementing a `neo.rawio` Class is not required, but recommended. Several extractors (especially) for :code:`Sorting`
266+
**NOTE:** implementing a `neo.rawio` class is not required, but recommended. Several extractors (especially) for :code:`Sorting`
248267
objects are implemented directly in SpikeInterface and inherit from the base classes.
249-
As examples, see the `CompressedBinaryIblExtractor <https://github.com/SpikeInterface/spikeinterface/blob/0.96.1/spikeinterface/extractors/cbin_ibl.py>`_
250-
for a :py:class:`~spikeinterface.core.BaseRecording` object, or the `SpykingCircusSortingExtractor <https://github.com/SpikeInterface/spikeinterface/blob/0.96.1/spikeinterface/extractors/spykingcircusextractors.py>`_
268+
As examples, see the `IblRecordingExtractor <https://github.com/SpikeInterface/spikeinterface/blob/main/src/spikeinterface/extractors/iblextractors.py>`_
269+
for a :py:class:`~spikeinterface.core.BaseRecording` object, or the `SpykingCircusSortingExtractor <https://github.com/SpikeInterface/spikeinterface/blob/main/src/spikeinterface/extractors/spykingcircusextractors.py>`_
251270
for a a :py:class:`~spikeinterface.core.BaseSorting` object.
252271

253272

@@ -290,7 +309,7 @@ Then, you can start creating a new class:
290309
291310
class MySpikeSorter(BaseSorter):
292311
"""
293-
Brief description (optional)
312+
Brief description
294313
"""
295314
296315
sorter_name = 'myspikesorter'
@@ -348,7 +367,7 @@ Now you can start filling out the required methods:
348367
def _check_apply_filter_in_params(cls, params):
349368
return False
350369
351-
#  optional
370+
# optional
352371
# can be implemented in subclass to check if the filter will be applied
353372
354373
@@ -369,10 +388,12 @@ Now you can start filling out the required methods:
369388
return sorting
370389
371390
When your spike sorter class is implemented, you have to add it to the list of available spike sorters in the
372-
`sorterlist.py`. Then you need to write a test in **tests/test_myspikesorter.py**. In order to be tested, you can
373-
install the required packages by changing the **pyproject.toml**. Note that MATLAB based tests cannot be run at the moment,
374-
but we recommend testing the implementation locally.
391+
`sorterlist.py <https://github.com/SpikeInterface/spikeinterface/blob/main/src/spikeinterface/sorters/sorterlist.py>`_ .
392+
Then you need to write a test in **tests/test_myspikesorter.py**. In order to be tested, you can
393+
install the required packages by changing the `pyproject.toml <https://github.com/SpikeInterface/spikeinterface/blob/main/pyproject.toml>`_.
394+
Note that MATLAB based tests cannot be run at the moment,but we recommend testing the implementation locally.
375395

376-
After this you need to add a block in **doc/sorters_info.rst** to describe your sorter.
396+
After this you need to add a block in `Install Sorters <https://github.com/SpikeInterface/spikeinterface/blob/main/doc/get_started/install_sorters.rst>`_
397+
to describe your sorter.
377398

378399
Finally, make a pull request so we can review the code and incorporate into the sorters module of SpikeInterface!

doc/get_started/quickstart.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,7 @@ available parameters are dictionaries and can be accessed with:
287287
'detect_threshold': 5,
288288
'freq_max': 5000.0,
289289
'freq_min': 400.0,
290-
'max_threads_per_process': 1,
290+
'max_threads_per_worker': 1,
291291
'mp_context': None,
292292
'n_jobs': 20,
293293
'nested_params': None,
@@ -673,7 +673,7 @@ compute quality metrics (some quality metrics require certain extensions
673673
'min_spikes': 0,
674674
'window_size_s': 1},
675675
'snr': {'peak_mode': 'extremum', 'peak_sign': 'neg'},
676-
'synchrony': {'synchrony_sizes': (2, 4, 8)}}
676+
'synchrony': {}
677677
678678
679679
Since the recording is very short, let’s change some parameters to
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
How to use a trained model to predict the curation labels
2+
=========================================================
3+
4+
For a more detailed guide to using trained models, `read our tutorial here
5+
<https://spikeinterface.readthedocs.io/en/latest/tutorials/curation/plot_1_automated_curation.html>`_).
6+
7+
There is a Collection of models for automated curation available on the
8+
`SpikeInterface HuggingFace page <https://huggingface.co/SpikeInterface>`_.
9+
10+
We'll apply the model ``toy_tetrode_model`` from ``SpikeInterface`` on a SortingAnalyzer
11+
called ``sorting_analyzer``. We assume that the quality and template metrics have
12+
already been computed.
13+
14+
We need to pass the ``sorting_analyzer``, the ``repo_id`` (which is just the part of the
15+
repo's URL after huggingface.co/) and that we trust the model.
16+
17+
.. code::
18+
19+
from spikeinterface.curation import auto_label_units
20+
21+
labels_and_probabilities = auto_label_units(
22+
sorting_analyzer = sorting_analyzer,
23+
repo_id = "SpikeInterface/toy_tetrode_model",
24+
trust_model = True
25+
)
26+
27+
If you have a local directory containing the model in a ``skops`` file you can use this to
28+
create the labels:
29+
30+
.. code::
31+
32+
labels_and_probabilities = si.auto_label_units(
33+
sorting_analyzer = sorting_analyzer,
34+
model_folder = "my_folder_with_a_model_in_it",
35+
)
36+
37+
The returned labels are a dictionary of model's predictions and it's confidence. These
38+
are also saved as a property of your ``sorting_analyzer`` and can be accessed like so:
39+
40+
.. code::
41+
42+
labels = sorting_analyzer.sorting.get_property("classifier_label")
43+
probabilities = sorting_analyzer.sorting.get_property("classifier_probability")
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
How to train a model to predict curation labels
2+
===============================================
3+
4+
A full tutorial for model-based curation can be found `here <https://spikeinterface.readthedocs.io/en/latest/tutorials/curation/plot_2_train_a_model.html>`_.
5+
6+
Here, we assume that you have:
7+
8+
* Two SortingAnalyzers called ``analyzer_1`` and
9+
``analyzer_2``, and have calculated some template and quality metrics for both
10+
* Manually curated labels for the units in each analyzer, in lists called
11+
``analyzer_1_labels`` and ``analyzer_2_labels``. If you have used phy, the lists can
12+
be accessed using ``curated_labels = analyzer.sorting.get_property("quality")``.
13+
14+
With these objects calculated, you can train a model as follows
15+
16+
.. code::
17+
18+
from spikeinterface.curation import train_model
19+
20+
analyzer_list = [analyzer_1, analyzer_2]
21+
labels_list = [analyzer_1_labels, analyzer_2_labels]
22+
output_folder = "/path/to/output_folder"
23+
24+
trainer = train_model(
25+
mode="analyzers",
26+
labels=labels_list,
27+
analyzers=analyzer_list,
28+
output_folder=output_folder,
29+
metric_names=None, # Set if you want to use a subset of metrics, defaults to all calculated quality and template metrics
30+
imputation_strategies=None, # Default is all available imputation strategies
31+
scaling_techniques=None, # Default is all available scaling techniques
32+
classifiers=None, # Defaults to Random Forest classifier only - we usually find this gives the best results, but a range of classifiers is available
33+
seed=None, # Set a seed for reproducibility
34+
)
35+
36+
37+
The trainer tries several models and chooses the most accurate one. This model and
38+
some metadata are stored in the ``output_folder``, which can later be loaded using the
39+
``load_model`` function (`more details <https://spikeinterface.readthedocs.io/en/latest/tutorials/curation/plot_1_automated_curation.html#download-a-pretrained-model>`_).
40+
We can also access the model, which is an sklearn ``Pipeline``, from the trainer object
41+
42+
.. code::
43+
44+
best_model = trainer.best_pipeline
45+
46+
47+
The training function can also be run in “csv” mode, if you prefer to
48+
store metrics in as .csv files. If the target labels are stored as a column in
49+
the file, you can point to these with the ``target_label`` parameter
50+
51+
.. code::
52+
53+
trainer = train_model(
54+
mode="csv",
55+
metrics_paths = ["/path/to/csv_file_1", "/path/to/csv_file_2"],
56+
target_label = "my_label",
57+
output_folder=output_folder,
58+
)

doc/how_to/benchmark_with_hybrid_recordings.rst

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2531,9 +2531,8 @@ Although non of the sorters find all units perfectly, ``Kilosort2.5``,
25312531
``Kilosort4``, and ``SpyKING CIRCUS 2`` all find around 10-12 hybrid
25322532
units with accuracy greater than 80%. ``Kilosort4`` has a better overall
25332533
curve, being able to find almost all units with an accuracy above 50%.
2534-
``Kilosort2.5`` performs well when looking at precision (finding all
2535-
spikes in a hybrid unit), at the cost of lower recall (finding spikes
2536-
when it shouldn’t).
2534+
``Kilosort2.5`` performs well when looking at precision (not finding spikes
2535+
when it shouldn’t), but it has a lower recall (finding all spikes in the ground truth).
25372536

25382537
In this example, we showed how to:
25392538

0 commit comments

Comments
 (0)