Skip to content

Commit 03676e0

Browse files
authored
Merge branch 'main' into main
2 parents afdea78 + ed07e25 commit 03676e0

134 files changed

Lines changed: 3898 additions & 1236 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.

.github/actions/build-test-environment/action.yml

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,7 @@ runs:
1515
shell: bash
1616
run: |
1717
pip install datalad-installer
18-
wget https://downloads.kitenet.net/git-annex/linux/current/git-annex-standalone-amd64.tar.gz
19-
mkdir /home/runner/work/installation
20-
mv git-annex-standalone-amd64.tar.gz /home/runner/work/installation/
21-
workdir=$(pwd)
22-
cd /home/runner/work/installation
23-
tar xvzf git-annex-standalone-amd64.tar.gz
24-
echo "$(pwd)/git-annex.linux" >> $GITHUB_PATH
25-
cd $workdir
18+
datalad-installer --sudo ok git-annex --method datalad/packages
2619
git config --global filter.annex.process "git-annex filter-process" # recommended for efficiency
2720
- name: Force installation of latest dev from key-packages when running dev (not release)
2821
run: |

.github/workflows/all-tests.yml

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -107,14 +107,7 @@ jobs:
107107
run: |
108108
pip install datalad-installer
109109
if [ ${{ runner.os }} = 'Linux' ]; then
110-
wget https://downloads.kitenet.net/git-annex/linux/current/git-annex-standalone-amd64.tar.gz
111-
mkdir /home/runner/work/installation
112-
mv git-annex-standalone-amd64.tar.gz /home/runner/work/installation/
113-
workdir=$(pwd)
114-
cd /home/runner/work/installation
115-
tar xvzf git-annex-standalone-amd64.tar.gz
116-
echo "$(pwd)/git-annex.linux" >> $GITHUB_PATH
117-
cd $workdir
110+
datalad-installer --sudo ok git-annex --method datalad/packages
118111
elif [ ${{ runner.os }} = 'macOS' ]; then
119112
datalad-installer --sudo ok git-annex --method brew
120113
elif [ ${{ runner.os }} = 'Windows' ]; then

doc/api.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ Non-NEO-based
153153
.. autofunction:: toy_example
154154
.. autofunction:: read_tridesclous
155155
.. autofunction:: read_waveclus
156+
.. autofunction:: read_whitematter
156157
.. autofunction:: read_yass
157158

158159

@@ -335,6 +336,7 @@ spikeinterface.exporters
335336
.. automodule:: spikeinterface.exporters
336337

337338
.. autofunction:: export_to_phy
339+
.. autofunction:: export_to_ibl_gui
338340
.. autofunction:: export_report
339341

340342

doc/development/development.rst

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -397,3 +397,52 @@ After this you need to add a block in `Install Sorters <https://github.com/Spike
397397
to describe your sorter.
398398

399399
Finally, make a pull request so we can review the code and incorporate into the sorters module of SpikeInterface!
400+
401+
402+
403+
How to make a release
404+
---------------------
405+
406+
Checklist
407+
^^^^^^^^^
408+
* pyproject.toml: check that the version is ahead of current release. Also, comment out the @ (git dependencies)
409+
* In the top level ``__init__`` (located at ``src/spikeinterface/__init__.py``) set ``DEV_MODE`` to ``False`` (this is used for the docker installations)
410+
* Create a new release note for the appropriate version on doc/releases/new_version_tag.
411+
412+
There can be large releases like:
413+
414+
``doc/releases/0.101.0.rst``
415+
416+
Which contain a section called "Main Changes" and minor releases which include only bug fixes like:
417+
418+
``doc/releases/0.101.2.rst``
419+
420+
To collect all the PRs and bug fixes we have a script in:
421+
``doc/scripts/``
422+
called ``auto-release-notes.sh``. Run it with ``bash auto-release-notes.sh`` and it will create the release notes for the module specific changes.
423+
424+
The first time you run the script, GitHub will guide you through an authorization process if you've not already done so.
425+
426+
The signature of the script is:
427+
428+
.. code-block:: bash
429+
430+
bash auto-release-notes.sh <start_date> <end_date>
431+
432+
Where the start date is the date of the last release and the end date is the current date. Dates are in YYYY-MM-DD format
433+
434+
The date of the last release can be found on `PyPI <https://pypi.org/project/spikeinterface/>`_.
435+
436+
437+
As a specific example:
438+
.. code-block:: bash
439+
440+
bash auto-release-notes.sh 2025-02-19 2025-03-24
441+
442+
* Finish the release notes and merge
443+
* Locally tag the main branch with the newly merged release notes with the new version
444+
* Push the tag to the remote repository which will trigger the release action (.github/workflows/publish-to-pypi.yml)
445+
* Do an after-release `PR <https://github.com/SpikeInterface/spikeinterface/pull/3828/files>`_:
446+
- Uncomment the git installs in pyproject
447+
- Set ``DEV_MODE`` to ``True`` in the top level ``__init__`` (located at ``src/spikeinterface/__init__.py``)
448+
- Update `pyproject.toml` version one patch ahead or one minor if it is larger one.

doc/how_to/customize_a_plot.rst

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
Customize a plot
2+
================
3+
4+
The ``SpikeInterface`` widgets are designed to have reasonable default
5+
plotting options, but sometimes you’ll want to make adjustments to the
6+
plots. The plotting functions all return a ``Widget`` object. These
7+
contain and give you access to the underlying matplotlib figure and
8+
axis, which you can apply any matplotlib machinery to. Let’s see how to
9+
do this in an example, by first making some synthetic data and computing
10+
extensions which can be used for plotting.
11+
12+
.. code::
13+
14+
import spikeinterface.full as si
15+
import matplotlib.pyplot as plt
16+
17+
recording, sorting = si.generate_ground_truth_recording(seed=1205)
18+
sorting_analyzer = si.create_sorting_analyzer(sorting=sorting, recording=recording)
19+
sorting_analyzer.compute({"random_spikes": {'seed': 1205}, "templates": {}, "unit_locations": {}})
20+
21+
unit_locations = sorting_analyzer.get_extension("unit_locations").get_data()
22+
23+
24+
25+
.. parsed-literal::
26+
27+
estimate_sparsity (no parallelization): 0%| | 0/10 [00:00<?, ?it/s]
28+
29+
30+
31+
.. parsed-literal::
32+
33+
estimate_templates_with_accumulator (no parallelization): 0%| | 0/10 [00:00<?, ?it/s]
34+
35+
36+
Now we can plot the ``unit_locations`` and ``unit_templates`` using the
37+
appropriate widgets (see the `full list of
38+
widgets <https://spikeinterface.readthedocs.io/en/stable/modules/widgets.html#available-plotting-functions>`__
39+
for more!). These functions output a ``Widget object``. We’ll assign the
40+
unit locations widget to ``fig_units``.
41+
42+
.. code::
43+
44+
fig_units = si.plot_unit_locations(sorting_analyzer)
45+
46+
# Each widget contains a `matplotlib` figure and axis:
47+
print(type(fig_units.figure))
48+
print(type(fig_units.ax))
49+
50+
51+
.. parsed-literal::
52+
53+
<class 'matplotlib.figure.Figure'>
54+
<class 'matplotlib.axes._axes.Axes'>
55+
56+
57+
58+
.. image:: customize_a_plot_files/customize_a_plot_4_1.png
59+
60+
61+
By gaining access to the matplotlib objects, we are able to utilize the
62+
full ``matplotlib`` machinery: adding custom titles, axis labels, ticks,
63+
more plots etc. Let’s customize our unit locations plot. (Note: the
64+
``SpikeInterface`` Team does not endorse the following style
65+
conventions):
66+
67+
.. code::
68+
69+
# Get the widget
70+
fig_units = si.plot_unit_locations(sorting_analyzer)
71+
72+
# Modify the widget's `axis`` to set the title and axes labels
73+
fig_units.ax.set_title("My favorite units", fontname = "Comic Sans MS")
74+
fig_units.ax.set_xlabel("x probe location (um)")
75+
fig_units.ax.set_ylabel("y probe location (um)")
76+
77+
# You can also set custom ticks
78+
fig_units.ax.set_xticks([-60,-30,unit_locations[0,0],30,60])
79+
fig_units.ax.set_xticklabels([-60,-30,"unit_0_x",30,60])
80+
fig_units.ax.set_yticks([-40,-20,0,unit_locations[0,1],40])
81+
fig_units.ax.set_yticklabels([-40,-20,0,"unit_0_y",40])
82+
83+
# Change the limits of the plot
84+
fig_units.ax.set_xlim((-30,50))
85+
fig_units.ax.set_ylim((-50,50))
86+
87+
# And add extra information on the plot
88+
fig_units.ax.text(unit_locations[6,0], unit_locations[6,1]+5, s="UNIT 6!!!", fontname="Courier")
89+
90+
fig_units
91+
92+
93+
94+
95+
.. parsed-literal::
96+
97+
<spikeinterface.widgets.unit_locations.UnitLocationsWidget at 0x147a81520>
98+
99+
100+
101+
102+
.. image:: customize_a_plot_files/customize_a_plot_6_1.png
103+
104+
105+
Beautiful!!!
106+
107+
You can also combine figures into a multi-figure plot. The easiest way
108+
to do this is to set up your figure and axes first, then tell
109+
``SpikeInterface`` which axes it should attach the widget plot to.
110+
Here’s an example of making a unit summary plot.
111+
112+
.. code::
113+
114+
import matplotlib.pyplot as plt
115+
fig, axs = plt.subplots(ncols=2, nrows=1)
116+
117+
unit_id=8
118+
si.plot_unit_locations(sorting_analyzer=sorting_analyzer, ax=axs[0])
119+
si.plot_unit_templates(sorting_analyzer, axes=[axs[1]], unit_ids=[f'{unit_id}'])
120+
121+
axs[0].plot([unit_locations[8,0], unit_locations[8,0]+50], [unit_locations[8,1], unit_locations[8,1]+50])
122+
axs[0].text(unit_locations[8,0]+52, unit_locations[8,1]+52, s=f"Unit {unit_id}")
123+
axs[0].set_title("Unit location", fontsize=10)
124+
125+
fig.suptitle(f"Unit {unit_id} summary", fontfamily="Comic Sans MS", fontsize=20)
126+
127+
fig.tight_layout()
128+
129+
130+
131+
132+
.. image:: customize_a_plot_files/customize_a_plot_8_1.png
133+
134+
135+
For more details on what you can do using matplotlib, check out their
136+
`extensive documentation <https://matplotlib.org/stable/>`__
24.8 KB
Loading
35.2 KB
Loading
53.5 KB
Loading

doc/how_to/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,4 @@ Guides on how to solve specific, short problems in SpikeInterface. Learn how to.
1717
drift_with_lfp
1818
auto_curation_training
1919
auto_curation_prediction
20+
customize_a_plot

doc/modules/exporters.rst

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ The input of the :py:func:`~spikeinterface.exporters.export_to_phy` is a :code:`
2525
.. code-block:: python
2626
2727
import spikeinterface as si # core module only
28-
from spikeinterface.postprocessing import compute_spike_amplitudes, compute_principal_components
2928
from spikeinterface.exporters import export_to_phy
3029
3130
# the waveforms are sparse so it is faster to export to phy
@@ -40,6 +39,41 @@ The input of the :py:func:`~spikeinterface.exporters.export_to_phy` is a :code:`
4039
export_to_phy(sorting_analyzer=sorting_analyzer, output_folder='path/to/phy_folder')
4140
4241
42+
Export to IBL GUI
43+
-----------------
44+
45+
The :py:func:`~spikeinterface.exporters.export_to_ibl_gui` function allows you to use the
46+
`IBL GUI <https://github.com/int-brain-lab/iblapps/wiki>`_ for probe alignment.
47+
48+
The IBL GUI can also be installed as a standalone app using `this fork <https://github.com/AllenNeuralDynamics/ibl-ephys-alignment-gui>`_ from the Allen Institute.
49+
50+
The input of the :py:func:`~spikeinterface.exporters.export_to_ibl_gui` is a :code:`SortingAnalyzer` object.
51+
52+
.. code-block:: python
53+
54+
import spikeinterface as si # core module only
55+
import spikeinterface.preprocessing as spre
56+
from spikeinterface.exporters import export_to_ibl_gui
57+
58+
sorting_analyzer = si.create_sorting_analyzer(sorting=sorting, recording=recording)
59+
60+
# we need to compute some required extensions
61+
sorting_analyzer.compute(['random_spikes', 'templates', 'spike_amplitudes', 'spike_locations', 'noise_levels', 'quality_metrics'])
62+
# note that spike_locations are optional, but recommended to compute accurate spike depths
63+
64+
# optionally, we can pass an LFP recording to compute RMS/PSD in the LFP band
65+
recording_lfp = spre.bandpass_filter(recording, freq_min=1, freq_max=300)
66+
# we can also decimate the LFP to speed up the process
67+
recording_lfp = spre.decimate(recording_lfp, 10)
68+
69+
# the export process is fast because everything is pre-computed
70+
export_to_ibl_gui(
71+
sorting_analyzer=sorting_analyzer,
72+
output_folder='path/to/ibl_folder',
73+
lfp_recording=recording_lfp,
74+
n_jobs=-1
75+
)
76+
4377
4478
Export a spike sorting report
4579
-----------------------------
@@ -68,8 +102,6 @@ with many units!
68102
.. code-block:: python
69103
70104
import spikeinterface as si # core module only
71-
from spikeinterface.postprocessing import compute_spike_amplitudes, compute_correlograms
72-
from spikeinterface.qualitymetrics import compute_quality_metrics
73105
from spikeinterface.exporters import export_report
74106
75107

0 commit comments

Comments
 (0)