Skip to content

Commit 7b8f181

Browse files
authored
Merge pull request #3299 from jonahpearl/sortingview_qms
allow quality and template metrics in sortingview's unit table
2 parents ff930d2 + 5495957 commit 7b8f181

2 files changed

Lines changed: 62 additions & 6 deletions

File tree

src/spikeinterface/widgets/sorting_summary.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,12 @@ class SortingSummaryWidget(BaseWidget):
4343
List of labels to be added to the curation table
4444
(sortingview backend)
4545
unit_table_properties : list or None, default: None
46-
List of properties to be added to the unit table
46+
List of properties to be added to the unit table.
47+
These may be drawn from the sorting extractor, and, if available,
48+
the quality_metrics and template_metrics extensions of the SortingAnalyzer.
49+
See all properties available with sorting.get_property_keys(), and, if available,
50+
analyzer.get_extension("quality_metrics").get_data().columns and
51+
analyzer.get_extension("template_metrics").get_data().columns.
4752
(sortingview backend)
4853
"""
4954

@@ -151,7 +156,7 @@ def plot_sortingview(self, data_plot, **backend_kwargs):
151156

152157
# unit ids
153158
v_units_table = generate_unit_table_view(
154-
dp.sorting_analyzer.sorting, dp.unit_table_properties, similarity_scores=similarity_scores
159+
dp.sorting_analyzer, dp.unit_table_properties, similarity_scores=similarity_scores
155160
)
156161

157162
if dp.curation:

src/spikeinterface/widgets/utils_sortingview.py

Lines changed: 55 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import numpy as np
44

55
from ..core.core_tools import check_json
6+
from warnings import warn
67

78

89
def make_serializable(*args):
@@ -45,9 +46,33 @@ def handle_display_and_url(widget, view, **backend_kwargs):
4546
return url
4647

4748

48-
def generate_unit_table_view(sorting, unit_properties=None, similarity_scores=None):
49+
def generate_unit_table_view(analyzer, unit_properties=None, similarity_scores=None):
4950
import sortingview.views as vv
5051

52+
sorting = analyzer.sorting
53+
54+
# Find available unit properties from all sources
55+
sorting_props = list(sorting.get_property_keys())
56+
if analyzer.get_extension("quality_metrics") is not None:
57+
qm_props = list(analyzer.get_extension("quality_metrics").get_data().columns)
58+
qm_data = analyzer.get_extension("quality_metrics").get_data()
59+
else:
60+
qm_props = []
61+
if analyzer.get_extension("template_metrics") is not None:
62+
tm_props = list(analyzer.get_extension("template_metrics").get_data().columns)
63+
tm_data = analyzer.get_extension("template_metrics").get_data()
64+
else:
65+
tm_props = []
66+
67+
# Check for any overlaps and warn user if any
68+
all_props = sorting_props + qm_props + tm_props
69+
overlap_props = [prop for prop in all_props if all_props.count(prop) > 1]
70+
if len(overlap_props) > 0:
71+
warn(
72+
f"Warning: Overlapping properties found in sorting, quality_metrics, and template_metrics: {overlap_props}"
73+
)
74+
75+
# Get unit properties
5176
if unit_properties is None:
5277
ut_columns = []
5378
ut_rows = [vv.UnitsTableRow(unit_id=u, values={}) for u in sorting.unit_ids]
@@ -56,8 +81,20 @@ def generate_unit_table_view(sorting, unit_properties=None, similarity_scores=No
5681
ut_rows = []
5782
values = {}
5883
valid_unit_properties = []
84+
85+
# Create columns for each property
5986
for prop_name in unit_properties:
60-
property_values = sorting.get_property(prop_name)
87+
88+
# Get property values from correct location
89+
if prop_name in sorting_props:
90+
property_values = sorting.get_property(prop_name)
91+
elif prop_name in qm_props:
92+
property_values = qm_data[prop_name].values
93+
elif prop_name in tm_props:
94+
property_values = tm_data[prop_name].values
95+
else:
96+
raise ValueError(f"Property '{prop_name}' not found in sorting, quality_metrics, or template_metrics")
97+
6198
# make dtype available
6299
val0 = np.array(property_values[0])
63100
if val0.dtype.kind in ("i", "u"):
@@ -74,14 +111,28 @@ def generate_unit_table_view(sorting, unit_properties=None, similarity_scores=No
74111
ut_columns.append(vv.UnitsTableColumn(key=prop_name, label=prop_name, dtype=dtype))
75112
valid_unit_properties.append(prop_name)
76113

114+
# Create rows for each unit
77115
for ui, unit in enumerate(sorting.unit_ids):
78116
for prop_name in valid_unit_properties:
79-
property_values = sorting.get_property(prop_name)
117+
118+
# Get property values from correct location
119+
if prop_name in sorting_props:
120+
property_values = sorting.get_property(prop_name)
121+
elif prop_name in qm_props:
122+
property_values = qm_data[prop_name].values
123+
elif prop_name in tm_props:
124+
property_values = tm_data[prop_name].values
125+
else:
126+
raise ValueError(
127+
f"Property '{prop_name}' not found in sorting, quality_metrics, or template_metrics"
128+
)
129+
130+
# Check for NaN values
80131
val0 = np.array(property_values[0])
81132
if val0.dtype.kind == "f":
82133
if np.isnan(property_values[ui]):
83134
continue
84-
values[prop_name] = property_values[ui]
135+
values[prop_name] = np.format_float_positional(property_values[ui], precision=4, fractional=False)
85136
ut_rows.append(vv.UnitsTableRow(unit_id=unit, values=check_json(values)))
86137

87138
v_units_table = vv.UnitsTable(rows=ut_rows, columns=ut_columns, similarity_scores=similarity_scores)

0 commit comments

Comments
 (0)