Skip to content

Commit d7b88dd

Browse files
authored
Merge branch 'main' into MGAMZ-Improve_job_kwarg_violation_hint
2 parents 6cfed62 + 8533a52 commit d7b88dd

33 files changed

Lines changed: 668 additions & 265 deletions

examples/tutorials/comparison/generate_erroneous_sorting.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,8 @@ def generate_erroneous_sorting():
4444
units_err = {}
4545

4646
# sorting_true have 10 units
47-
np.random.seed(0)
47+
# np.random.seed(0)
48+
rng = np.random.default_rng(seed=0)
4849

4950
# unit 1 2 are perfect
5051
for u in [1, 2]:
@@ -54,29 +55,29 @@ def generate_erroneous_sorting():
5455
# unit 3 4 (medium) 10 (low) have medium to low agreement
5556
for u, score in [(3, 0.8), (4, 0.75), (10, 0.3)]:
5657
st = sorting_true.get_unit_spike_train(u)
57-
st = np.sort(np.random.choice(st, size=int(st.size * score), replace=False))
58+
st = np.sort(rng.choice(st, size=int(st.size * score), replace=False))
5859
units_err[u] = st
5960

6061
# unit 5 6 are over merge
6162
st5 = sorting_true.get_unit_spike_train(5)
6263
st6 = sorting_true.get_unit_spike_train(6)
6364
st = np.unique(np.concatenate([st5, st6]))
64-
st = np.sort(np.random.choice(st, size=int(st.size * 0.7), replace=False))
65+
st = np.sort(rng.choice(st, size=int(st.size * 0.7), replace=False))
6566
units_err[56] = st
6667

6768
# unit 7 is over split in 2 part
6869
st7 = sorting_true.get_unit_spike_train(7)
6970
st70 = st7[::2]
7071
units_err[70] = st70
7172
st71 = st7[1::2]
72-
st71 = np.sort(np.random.choice(st71, size=int(st71.size * 0.9), replace=False))
73+
st71 = np.sort(rng.choice(st71, size=int(st71.size * 0.9), replace=False))
7374
units_err[71] = st71
7475

7576
# unit 8 is redundant 3 times
7677
st8 = sorting_true.get_unit_spike_train(8)
77-
st80 = np.sort(np.random.choice(st8, size=int(st8.size * 0.65), replace=False))
78-
st81 = np.sort(np.random.choice(st8, size=int(st8.size * 0.6), replace=False))
79-
st82 = np.sort(np.random.choice(st8, size=int(st8.size * 0.55), replace=False))
78+
st80 = np.sort(rng.choice(st8, size=int(st8.size * 0.65), replace=False))
79+
st81 = np.sort(rng.choice(st8, size=int(st8.size * 0.6), replace=False))
80+
st82 = np.sort(rng.choice(st8, size=int(st8.size * 0.55), replace=False))
8081
units_err[80] = st80
8182
units_err[81] = st81
8283
units_err[82] = st82

src/spikeinterface/benchmark/benchmark_clustering.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,11 @@ def plot_performances_vs_snr(self, **kwargs):
192192

193193
return plot_performances_vs_snr(self, **kwargs)
194194

195+
def plot_performances_vs_firing_rate(self, **kwargs):
196+
from .benchmark_plot_tools import plot_performances_vs_firing_rate
197+
198+
return plot_performances_vs_firing_rate(self, **kwargs)
199+
195200
def plot_performances_comparison(self, *args, **kwargs):
196201
from .benchmark_plot_tools import plot_performances_comparison
197202

src/spikeinterface/benchmark/benchmark_plot_tools.py

Lines changed: 158 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -373,7 +373,8 @@ def plot_agreement_matrix(study, ordered=True, case_keys=None, axs=None):
373373

374374
num_axes = len(case_keys)
375375
if axs is None:
376-
fig, axs = plt.subplots(ncols=num_axes, squeeze=True)
376+
fig, axs = plt.subplots(ncols=num_axes, squeeze=False)
377+
axs = axs[0, :]
377378
else:
378379
assert len(axs) == num_axes, "axs should have the same number of axes as case_keys"
379380
fig = axs[0].get_figure()
@@ -399,12 +400,13 @@ def plot_agreement_matrix(study, ordered=True, case_keys=None, axs=None):
399400
return fig
400401

401402

402-
def plot_performances_vs_snr(
403+
def _plot_performances_vs_metric(
403404
study,
405+
metric_name,
404406
case_keys=None,
405407
figsize=None,
406408
performance_names=("accuracy", "recall", "precision"),
407-
snr_dataset_reference=None,
409+
metric_dataset_reference=None,
408410
levels_to_group_by=None,
409411
orientation="vertical",
410412
show_legend=True,
@@ -414,43 +416,6 @@ def plot_performances_vs_snr(
414416
num_bin_average=20,
415417
axs=None,
416418
):
417-
"""
418-
Plots performance metrics against signal-to-noise ratio (SNR) for different cases in a study.
419-
420-
Parameters
421-
----------
422-
study : object
423-
The study object containing the cases and results.
424-
case_keys : list | None, default: None
425-
List of case keys to include in the plot. If None, all cases in the study are included.
426-
figsize : tuple | None, default: None
427-
Size of the figure.
428-
performance_names : tuple, default: ("accuracy", "recall", "precision")
429-
Names of the performance metrics to plot. Default is ("accuracy", "recall", "precision").
430-
snr_dataset_reference : str | None, default: None
431-
Reference dataset key to use for SNR. If None, the SNR of each dataset is used.
432-
levels_to_group_by : list | None, default: None
433-
Levels to group by when mapping case keys.
434-
orientation : "vertical" | "horizontal", default: "vertical"
435-
The orientation of the plot.
436-
show_legend : bool, default True
437-
Show legend or not
438-
show_sigmoid_fit : bool, default True
439-
Show sigmoid that fit the performances.
440-
show_average_by_bin : bool, default False
441-
Instead of the sigmoid an average by bins can be plotted.
442-
scatter_size : int, default 4
443-
scatter size
444-
num_bin_average : int, default 2
445-
Num bin for average
446-
axs : matplotlib.axes.Axes | None, default: None
447-
The axs to use for plotting. Should be the same size as len(performance_names).
448-
449-
Returns
450-
-------
451-
fig : matplotlib.figure.Figure
452-
The resulting figure containing the plots.
453-
"""
454419
import matplotlib.pyplot as plt
455420

456421
if case_keys is None:
@@ -499,15 +464,15 @@ def plot_performances_vs_snr(
499464
all_xs = []
500465
all_ys = []
501466
for sub_key in key_list:
502-
if snr_dataset_reference is None:
467+
if metric_dataset_reference is None:
503468
# use the SNR of each dataset
504469
analyzer = study.get_sorting_analyzer(sub_key)
505470
else:
506471
# use the same SNR from a reference dataset
507-
analyzer = study.get_sorting_analyzer(dataset_key=snr_dataset_reference)
472+
analyzer = study.get_sorting_analyzer(dataset_key=metric_dataset_reference)
508473

509474
quality_metrics = analyzer.get_extension("quality_metrics").get_data()
510-
x = quality_metrics["snr"].to_numpy(dtype="float64")
475+
x = quality_metrics[metric_name].to_numpy(dtype="float64")
511476
y = (
512477
study.get_result(sub_key)["gt_comparison"]
513478
.get_performance()[performance_name]
@@ -564,6 +529,148 @@ def plot_performances_vs_snr(
564529
return fig
565530

566531

532+
def plot_performances_vs_snr(
533+
study,
534+
case_keys=None,
535+
figsize=None,
536+
performance_names=("accuracy", "recall", "precision"),
537+
metric_dataset_reference=None,
538+
levels_to_group_by=None,
539+
orientation="vertical",
540+
show_legend=True,
541+
with_sigmoid_fit=False,
542+
show_average_by_bin=True,
543+
scatter_size=4,
544+
num_bin_average=20,
545+
axs=None,
546+
):
547+
"""
548+
Plots performance metrics against signal-to-noise ratio (SNR) for different cases in a study.
549+
550+
Parameters
551+
----------
552+
study : object
553+
The study object containing the cases and results.
554+
case_keys : list | None, default: None
555+
List of case keys to include in the plot. If None, all cases in the study are included.
556+
figsize : tuple | None, default: None
557+
Size of the figure.
558+
performance_names : tuple, default: ("accuracy", "recall", "precision")
559+
Names of the performance metrics to plot. Default is ("accuracy", "recall", "precision").
560+
metric_dataset_reference : str | None, default: None
561+
Reference dataset metric key to use. If None, the SNR of each dataset is used.
562+
levels_to_group_by : list | None, default: None
563+
Levels to group by when mapping case keys.
564+
orientation : "vertical" | "horizontal", default: "vertical"
565+
The orientation of the plot.
566+
show_legend : bool, default True
567+
Show legend or not
568+
show_sigmoid_fit : bool, default True
569+
Show sigmoid that fit the performances.
570+
show_average_by_bin : bool, default False
571+
Instead of the sigmoid an average by bins can be plotted.
572+
scatter_size : int, default 4
573+
scatter size
574+
num_bin_average : int, default 2
575+
Num bin for average
576+
axs : matplotlib.axes.Axes | None, default: None
577+
The axs to use for plotting. Should be the same size as len(performance_names).
578+
579+
Returns
580+
-------
581+
fig : matplotlib.figure.Figure
582+
The resulting figure containing the plots.
583+
"""
584+
585+
return _plot_performances_vs_metric(
586+
study,
587+
"snr",
588+
case_keys=case_keys,
589+
figsize=figsize,
590+
performance_names=performance_names,
591+
metric_dataset_reference=metric_dataset_reference,
592+
levels_to_group_by=levels_to_group_by,
593+
orientation=orientation,
594+
show_legend=show_legend,
595+
with_sigmoid_fit=with_sigmoid_fit,
596+
show_average_by_bin=show_average_by_bin,
597+
scatter_size=scatter_size,
598+
num_bin_average=num_bin_average,
599+
axs=axs,
600+
)
601+
602+
603+
def plot_performances_vs_firing_rate(
604+
study,
605+
case_keys=None,
606+
figsize=None,
607+
performance_names=("accuracy", "recall", "precision"),
608+
metric_dataset_reference=None,
609+
levels_to_group_by=None,
610+
orientation="vertical",
611+
show_legend=True,
612+
with_sigmoid_fit=False,
613+
show_average_by_bin=True,
614+
scatter_size=4,
615+
num_bin_average=20,
616+
axs=None,
617+
):
618+
"""
619+
Plots performance metrics against firing rate for different cases in a study.
620+
621+
Parameters
622+
----------
623+
study : object
624+
The study object containing the cases and results.
625+
case_keys : list | None, default: None
626+
List of case keys to include in the plot. If None, all cases in the study are included.
627+
figsize : tuple | None, default: None
628+
Size of the figure.
629+
performance_names : tuple, default: ("accuracy", "recall", "precision")
630+
Names of the performance metrics to plot. Default is ("accuracy", "recall", "precision").
631+
metric_dataset_reference : str | None, default: None
632+
Reference dataset metric key to use. If None, the SNR of each dataset is used.
633+
levels_to_group_by : list | None, default: None
634+
Levels to group by when mapping case keys.
635+
orientation : "vertical" | "horizontal", default: "vertical"
636+
The orientation of the plot.
637+
show_legend : bool, default True
638+
Show legend or not
639+
show_sigmoid_fit : bool, default True
640+
Show sigmoid that fit the performances.
641+
show_average_by_bin : bool, default False
642+
Instead of the sigmoid an average by bins can be plotted.
643+
scatter_size : int, default 4
644+
scatter size
645+
num_bin_average : int, default 2
646+
Num bin for average
647+
axs : matplotlib.axes.Axes | None, default: None
648+
The axs to use for plotting. Should be the same size as len(performance_names).
649+
650+
Returns
651+
-------
652+
fig : matplotlib.figure.Figure
653+
The resulting figure containing the plots.
654+
"""
655+
656+
return _plot_performances_vs_metric(
657+
study,
658+
"firing_rate",
659+
case_keys=case_keys,
660+
figsize=figsize,
661+
performance_names=performance_names,
662+
metric_dataset_reference=metric_dataset_reference,
663+
levels_to_group_by=levels_to_group_by,
664+
orientation=orientation,
665+
show_legend=show_legend,
666+
with_sigmoid_fit=with_sigmoid_fit,
667+
show_average_by_bin=show_average_by_bin,
668+
scatter_size=scatter_size,
669+
num_bin_average=num_bin_average,
670+
axs=axs,
671+
)
672+
673+
567674
def plot_performances_ordered(
568675
study,
569676
case_keys=None,
@@ -614,9 +721,11 @@ def plot_performances_ordered(
614721

615722
if axs is None:
616723
if orientation == "vertical":
617-
fig, axs = plt.subplots(nrows=num_axes, figsize=figsize, squeeze=True)
724+
fig, axs = plt.subplots(nrows=num_axes, figsize=figsize, squeeze=False)
725+
axs = axs[:, 0]
618726
elif orientation == "horizontal":
619-
fig, axs = plt.subplots(ncols=num_axes, figsize=figsize, squeeze=True)
727+
fig, axs = plt.subplots(ncols=num_axes, figsize=figsize, squeeze=False)
728+
axs = axs[0, :]
620729
else:
621730
raise ValueError("orientation must be 'vertical' or 'horizontal'")
622731
else:
@@ -850,7 +959,8 @@ def plot_performances_vs_depth_and_snr(
850959
case_keys, labels = study.get_grouped_keys_mapping(levels_to_group_by=levels_to_group_by, case_keys=case_keys)
851960

852961
if axs is None:
853-
fig, axs = plt.subplots(ncols=len(case_keys), figsize=figsize, squeeze=True)
962+
fig, axs = plt.subplots(ncols=len(case_keys), figsize=figsize, squeeze=False)
963+
axs = axs[0, :]
854964
else:
855965
assert len(axs) == len(case_keys), "axs should have the same number of axes as case_keys"
856966
fig = axs[0].get_figure()
@@ -927,7 +1037,8 @@ def plot_performance_losses(
9271037
import matplotlib.pyplot as plt
9281038

9291039
if axs is None:
930-
fig, axs = plt.subplots(nrows=len(performance_names), figsize=figsize, squeeze=True)
1040+
fig, axs = plt.subplots(nrows=len(performance_names), figsize=figsize, squeeze=False)
1041+
axs = axs[:, 0]
9311042
else:
9321043
assert len(axs) == len(performance_names), "axs should have the same number of axes as performance_names"
9331044
fig = axs[0].get_figure()

src/spikeinterface/benchmark/benchmark_sorter.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,11 @@ def plot_performances_vs_snr(self, **kwargs):
8989

9090
return plot_performances_vs_snr(self, **kwargs)
9191

92+
def plot_performances_vs_firing_rate(self, **kwargs):
93+
from .benchmark_plot_tools import plot_performances_vs_firing_rate
94+
95+
return plot_performances_vs_firing_rate(self, **kwargs)
96+
9297
def plot_performances_ordered(self, **kwargs):
9398
from .benchmark_plot_tools import plot_performances_ordered
9499

0 commit comments

Comments
 (0)