Skip to content

Commit babb9aa

Browse files
authored
Merge branch 'main' into add-BaseRasterWidget
2 parents a758049 + 64d253c commit babb9aa

28 files changed

Lines changed: 942 additions & 192 deletions

pyproject.toml

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "spikeinterface"
3-
version = "0.102.1"
3+
version = "0.102.2"
44
authors = [
55
{ name="Alessio Buccino", email="alessiop.buccino@gmail.com" },
66
{ name="Samuel Garcia", email="sam.garcia.die@gmail.com" },
@@ -127,16 +127,16 @@ test_core = [
127127

128128
# for github test : probeinterface and neo from master
129129
# for release we need pypi, so this need to be commented
130-
# "probeinterface @ git+https://github.com/SpikeInterface/probeinterface.git",
131-
# "neo @ git+https://github.com/NeuralEnsemble/python-neo.git",
130+
"probeinterface @ git+https://github.com/SpikeInterface/probeinterface.git",
131+
"neo @ git+https://github.com/NeuralEnsemble/python-neo.git",
132132
]
133133

134134
test_extractors = [
135135
# Functions to download data in neo test suite
136136
"pooch>=1.8.2",
137137
"datalad>=1.0.2",
138-
# "probeinterface @ git+https://github.com/SpikeInterface/probeinterface.git",
139-
# "neo @ git+https://github.com/NeuralEnsemble/python-neo.git",
138+
"probeinterface @ git+https://github.com/SpikeInterface/probeinterface.git",
139+
"neo @ git+https://github.com/NeuralEnsemble/python-neo.git",
140140
]
141141

142142
test_preprocessing = [
@@ -175,8 +175,8 @@ test = [
175175

176176
# for github test : probeinterface and neo from master
177177
# for release we need pypi, so this need to be commented
178-
# "probeinterface @ git+https://github.com/SpikeInterface/probeinterface.git",
179-
# "neo @ git+https://github.com/NeuralEnsemble/python-neo.git",
178+
"probeinterface @ git+https://github.com/SpikeInterface/probeinterface.git",
179+
"neo @ git+https://github.com/NeuralEnsemble/python-neo.git",
180180
]
181181

182182
docs = [
@@ -201,8 +201,8 @@ docs = [
201201
"datalad>=1.0.2",
202202

203203
# for release we need pypi, so this needs to be commented
204-
# "probeinterface @ git+https://github.com/SpikeInterface/probeinterface.git", # We always build from the latest version
205-
# "neo @ git+https://github.com/NeuralEnsemble/python-neo.git", # We always build from the latest version
204+
"probeinterface @ git+https://github.com/SpikeInterface/probeinterface.git", # We always build from the latest version
205+
"neo @ git+https://github.com/NeuralEnsemble/python-neo.git", # We always build from the latest version
206206

207207
]
208208

src/spikeinterface/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,5 +27,5 @@
2727
# This flag must be set to False for release
2828
# This avoids using versioning that contains ".dev0" (and this is a better choice)
2929
# This is mainly useful when using run_sorter in a container and spikeinterface install
30-
# DEV_MODE = True
31-
DEV_MODE = False
30+
DEV_MODE = True
31+
# DEV_MODE = False

src/spikeinterface/benchmark/benchmark_base.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -228,11 +228,11 @@ def run(self, case_keys=None, keep=True, verbose=False, **job_kwargs):
228228
benchmark.result["run_time"] = float(t1 - t0)
229229
benchmark.save_main(bench_folder)
230230

231-
def set_colors(self, colors=None, map_name="tab20"):
231+
def set_colors(self, colors=None, map_name="tab10"):
232232
if colors is None:
233233
case_keys = list(self.cases.keys())
234234
self.colors = get_some_colors(
235-
case_keys, map_name=map_name, color_engine="matplotlib", shuffle=False, margin=0
235+
case_keys, map_name=map_name, color_engine="matplotlib", shuffle=False, margin=0, resample=False
236236
)
237237
else:
238238
self.colors = colors

src/spikeinterface/benchmark/benchmark_matching.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ def plot_unit_counts(self, case_keys=None, figsize=None):
138138

139139
plot_study_unit_counts(self, case_keys, figsize=figsize)
140140

141-
def plot_unit_losses(self, before, after, metric=["precision"], figsize=None):
141+
def plot_unit_losses(self, before, after, metric=["accuracy"], figsize=None):
142142
import matplotlib.pyplot as plt
143143

144144
fig, axs = plt.subplots(ncols=1, nrows=len(metric), figsize=figsize, squeeze=False)

src/spikeinterface/benchmark/benchmark_peak_detection.py

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
from .benchmark_base import Benchmark, BenchmarkStudy
1616
from spikeinterface.core.basesorting import minimum_spike_dtype
1717
from spikeinterface.core.sortinganalyzer import create_sorting_analyzer
18+
from .benchmark_plot_tools import fit_sigmoid, sigmoid
1819

1920

2021
class PeakDetectionBenchmark(Benchmark):
@@ -126,7 +127,7 @@ def create_benchmark(self, key):
126127
def plot_agreements_by_channels(self, case_keys=None, figsize=(15, 15)):
127128
if case_keys is None:
128129
case_keys = list(self.cases.keys())
129-
import pylab as plt
130+
import matplotlib.pyplot as plt
130131

131132
fig, axs = plt.subplots(ncols=len(case_keys), nrows=1, figsize=figsize, squeeze=False)
132133

@@ -138,7 +139,7 @@ def plot_agreements_by_channels(self, case_keys=None, figsize=(15, 15)):
138139
def plot_agreements_by_units(self, case_keys=None, figsize=(15, 15)):
139140
if case_keys is None:
140141
case_keys = list(self.cases.keys())
141-
import pylab as plt
142+
import matplotlib.pyplot as plt
142143

143144
fig, axs = plt.subplots(ncols=len(case_keys), nrows=1, figsize=figsize, squeeze=False)
144145

@@ -151,32 +152,39 @@ def plot_performances_vs_snr(self, case_keys=None, figsize=(15, 15), detect_thre
151152
if case_keys is None:
152153
case_keys = list(self.cases.keys())
153154

155+
import matplotlib.pyplot as plt
156+
154157
fig, axs = plt.subplots(ncols=1, nrows=3, figsize=figsize)
155158

156159
for count, k in enumerate(("accuracy", "recall", "precision")):
157160

158161
ax = axs[count]
159162
for key in case_keys:
163+
color = self.get_colors()[key]
160164
label = self.cases[key]["label"]
161165

162166
analyzer = self.get_sorting_analyzer(key)
163167
metrics = analyzer.get_extension("quality_metrics").get_data()
164168
x = metrics["snr"].values
165169
y = self.get_result(key)["sliced_gt_comparison"].get_performance()[k].values
166-
ax.scatter(x, y, marker=".", label=label)
170+
ax.scatter(x, y, marker=".", label=label, color=color)
167171
ax.set_title(k)
168172
if detect_threshold is not None:
169173
ymin, ymax = ax.get_ylim()
170174
ax.plot([detect_threshold, detect_threshold], [ymin, ymax], "k--")
171175

176+
popt = fit_sigmoid(x, y, p0=None)
177+
xfit = np.linspace(0, max(metrics["snr"].values), 100)
178+
ax.plot(xfit, sigmoid(xfit, *popt), color=color)
179+
172180
if count == 2:
173181
ax.legend()
174182

175183
def plot_detected_amplitudes(self, case_keys=None, figsize=(15, 5), detect_threshold=None):
176184

177185
if case_keys is None:
178186
case_keys = list(self.cases.keys())
179-
import pylab as plt
187+
import matplotlib.pyplot as plt
180188

181189
fig, axs = plt.subplots(ncols=len(case_keys), nrows=1, figsize=figsize, squeeze=False)
182190

@@ -201,7 +209,7 @@ def plot_deltas_per_cells(self, case_keys=None, figsize=(15, 5)):
201209

202210
if case_keys is None:
203211
case_keys = list(self.cases.keys())
204-
import pylab as plt
212+
import matplotlib.pyplot as plt
205213

206214
fig, axs = plt.subplots(ncols=len(case_keys), nrows=1, figsize=figsize, squeeze=False)
207215
for count, key in enumerate(case_keys):
@@ -222,12 +230,12 @@ def plot_template_similarities(self, case_keys=None, metric="l2", figsize=(15, 5
222230

223231
if case_keys is None:
224232
case_keys = list(self.cases.keys())
225-
import pylab as plt
233+
import matplotlib.pyplot as plt
226234

227235
fig, ax = plt.subplots(ncols=1, nrows=1, figsize=figsize, squeeze=True)
228236
for key in case_keys:
229237

230-
import sklearn
238+
import sklearn.metrics
231239

232240
gt_templates = self.get_result(key)["gt_templates"]
233241
found_templates = self.get_result(key)["templates"]
@@ -244,14 +252,22 @@ def plot_template_similarities(self, case_keys=None, metric="l2", figsize=(15, 5
244252
else:
245253
distances[i] = sklearn.metrics.pairwise_distances(a[None, :], b[None, :], metric)[0, 0]
246254

255+
color = self.get_colors()[key]
256+
247257
label = self.cases[key]["label"]
248258
analyzer = self.get_sorting_analyzer(key)
249259
metrics = analyzer.get_extension("quality_metrics").get_data()
250260
x = metrics["snr"].values
251-
ax.scatter(x, distances, marker=".", label=label)
252-
if detect_threshold is not None:
253-
ymin, ymax = ax.get_ylim()
254-
ax.plot([detect_threshold, detect_threshold], [ymin, ymax], "k--")
261+
y = distances
262+
ax.scatter(x, y, marker=".", label=label, color=color)
263+
264+
popt = fit_sigmoid(x, y, p0=None)
265+
xfit = np.linspace(0, max(metrics["snr"].values), 100)
266+
ax.plot(xfit, sigmoid(xfit, *popt), color=color)
267+
268+
if detect_threshold is not None:
269+
ymin, ymax = ax.get_ylim()
270+
ax.plot([detect_threshold, detect_threshold], [ymin, ymax], "k--")
255271

256272
ax.legend()
257273
ax.set_xlabel("snr")

src/spikeinterface/benchmark/benchmark_plot_tools.py

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import numpy as np
2+
import warnings
23

34

45
def _simpleaxis(ax):
@@ -193,7 +194,7 @@ def plot_agreement_matrix(study, ordered=True, case_keys=None):
193194
case_keys = list(study.cases.keys())
194195

195196
num_axes = len(case_keys)
196-
fig, axs = plt.subplots(ncols=num_axes)
197+
fig, axs = plt.subplots(ncols=num_axes, squeeze=False)
197198

198199
for count, key in enumerate(case_keys):
199200
ax = axs.flatten()[count]
@@ -214,7 +215,9 @@ def plot_agreement_matrix(study, ordered=True, case_keys=None):
214215
ax.set_xticks([])
215216

216217

217-
def plot_performances_vs_snr(study, case_keys=None, figsize=None, metrics=["accuracy", "recall", "precision"]):
218+
def plot_performances_vs_snr(
219+
study, case_keys=None, figsize=None, metrics=["accuracy", "recall", "precision"], snr_dataset_reference=None
220+
):
218221
import matplotlib.pyplot as plt
219222

220223
if case_keys is None:
@@ -228,7 +231,13 @@ def plot_performances_vs_snr(study, case_keys=None, figsize=None, metrics=["accu
228231
for key in case_keys:
229232
label = study.cases[key]["label"]
230233

231-
analyzer = study.get_sorting_analyzer(key)
234+
if snr_dataset_reference is None:
235+
# use the SNR of each dataset
236+
analyzer = study.get_sorting_analyzer(key)
237+
else:
238+
# use the same SNR from a reference dataset
239+
analyzer = study.get_sorting_analyzer(dataset_key=snr_dataset_reference)
240+
232241
metrics = analyzer.get_extension("quality_metrics").get_data()
233242
x = metrics["snr"].values
234243
y = study.get_result(key)["gt_comparison"].get_performance()[k].values
@@ -303,3 +312,16 @@ def plot_performances_comparison(
303312
ax.legend(handles=patches)
304313
fig.tight_layout()
305314
return fig
315+
316+
317+
def sigmoid(x, x0, k, b):
318+
with warnings.catch_warnings(action="ignore"):
319+
out = (1 / (1 + np.exp(-k * (x - x0)))) + b
320+
return out
321+
322+
323+
def fit_sigmoid(xdata, ydata, p0=None):
324+
from scipy.optimize import curve_fit
325+
326+
popt, pcov = curve_fit(sigmoid, xdata, ydata, p0)
327+
return popt

src/spikeinterface/core/binaryrecordingextractor.py

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,6 @@ class BinaryRecordingExtractor(BaseRecording):
2323
The sampling frequency
2424
num_channels : int
2525
Number of channels
26-
num_chan : int [deprecated, use num_channels instead, will be removed as early as v0.100.0]
27-
Number of channels
2826
dtype : str or dtype
2927
The dtype of the binary file
3028
time_axis : int, default: 0
@@ -57,23 +55,15 @@ def __init__(
5755
file_paths,
5856
sampling_frequency,
5957
dtype,
60-
num_channels=None,
58+
num_channels: int,
6159
t_starts=None,
6260
channel_ids=None,
6361
time_axis=0,
6462
file_offset=0,
6563
gain_to_uV=None,
6664
offset_to_uV=None,
6765
is_filtered=None,
68-
num_chan=None,
6966
):
70-
# This assigns num_channels if num_channels is not None, otherwise num_chan is assigned
71-
# num_chan needs to be be kept for backward compatibility but should not be used by the
72-
# end user
73-
num_channels = num_channels or num_chan
74-
assert num_channels is not None, "You must provide num_channels or num_chan"
75-
if num_chan is not None:
76-
warnings.warn("`num_chan` is to be deprecated as of version 0.100, please use `num_channels` instead")
7767

7868
if channel_ids is None:
7969
channel_ids = list(range(num_channels))

src/spikeinterface/core/motion.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,14 @@ def copy(self):
245245
interpolation_method=self.interpolation_method,
246246
)
247247

248+
def get_boundaries(self):
249+
max_ = -np.inf
250+
min_ = np.inf
251+
for segment_index, displacement_array in enumerate(self.displacement):
252+
min_ = min(min_, np.min(displacement_array))
253+
max_ = max(max_, np.max(displacement_array))
254+
return min_, max_
255+
248256

249257
def ensure_time_bins(time_bin_centers_s=None, time_bin_edges_s=None):
250258
"""Ensure that both bin edges and bin centers are present

src/spikeinterface/core/node_pipeline.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@
2929

3030

3131
class PipelineNode:
32+
33+
# If False (general case) then compute(traces_chunk, *node_input_args)
34+
# If True then compute(traces_chunk, start_frame, end_frame, segment_index, max_margin, *node_input_args)
35+
_compute_has_extended_signature = False
36+
3237
def __init__(
3338
self,
3439
recording: BaseRecording,
@@ -684,7 +689,13 @@ def _compute_peak_pipeline_chunk(segment_index, start_frame, end_frame, worker_c
684689
node_output = node.compute(traces_chunk, start_frame, end_frame, segment_index, max_margin, peak_slice)
685690
else:
686691
# TODO later when in master: change the signature of all nodes (or maybe not!)
687-
node_output = node.compute(traces_chunk, *node_input_args)
692+
if not node._compute_has_extended_signature:
693+
node_output = node.compute(traces_chunk, *node_input_args)
694+
else:
695+
node_output = node.compute(
696+
traces_chunk, start_frame, end_frame, segment_index, max_margin, *node_input_args
697+
)
698+
688699
pipeline_outputs[node] = node_output
689700

690701
if skip_after_n_peaks_per_worker is not None and isinstance(node, PeakSource):

src/spikeinterface/core/tests/test_binaryrecordingextractor.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,10 +93,8 @@ def test_sequential_reading_of_small_traces(folder_with_binary_files):
9393
dtype = "float32"
9494

9595
file_paths = [folder / "traces_cached_seg0.raw"]
96-
# `num_chan` is kept for backward compatibility so including it at least one test
97-
# run is good to ensure that it is appropriately accepted as an argument
9896
recording = BinaryRecordingExtractor(
99-
num_chan=num_channels,
97+
num_channels=num_channels,
10098
file_paths=file_paths,
10199
sampling_frequency=sampling_frequency,
102100
dtype=dtype,

0 commit comments

Comments
 (0)