Skip to content

Commit 23448c9

Browse files
committed
Avoid recursive calls when time changes and remove self.segment_index
1 parent 0f520a8 commit 23448c9

File tree

5 files changed

+59
-63
lines changed

5 files changed

+59
-63
lines changed

spikeinterface_gui/basescatterview.py

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -361,11 +361,11 @@ def _panel_make_layout(self):
361361

362362
self.lasso_tool = LassoSelectTool()
363363

364-
self.segment_index = 0
364+
segment_index = self.controller.get_time()[1]
365365
self.segment_selector = pn.widgets.Select(
366366
name="",
367367
options=[f"Segment {i}" for i in range(self.controller.num_segments)],
368-
value=f"Segment {self.segment_index}",
368+
value=f"Segment {segment_index}",
369369
)
370370
self.segment_selector.param.watch(self._panel_change_segment, 'value')
371371

@@ -466,9 +466,10 @@ def _panel_refresh(self):
466466
colors = []
467467

468468
segment_index = self.controller.get_time()[1]
469-
if segment_index != self.segment_index:
470-
self.segment_index = segment_index
471-
self.segment_selector.value = f"Segment {self.segment_index}"
469+
# get view segment index from segment selector
470+
segment_index_from_selector = self.segment_selector.options.index(self.segment_selector.value)
471+
if segment_index != segment_index_from_selector:
472+
self.segment_selector.value = f"Segment {segment_index}"
472473

473474
visible_unit_ids = self.controller.get_visible_unit_ids()
474475
for unit_id in visible_unit_ids:
@@ -531,8 +532,8 @@ def _panel_on_select_button(self, event):
531532

532533
def _panel_change_segment(self, event):
533534
self._current_selected = 0
534-
self.segment_index = int(self.segment_selector.value.split()[-1])
535-
self.controller.set_time(segment_index=self.segment_index)
535+
segment_index = int(self.segment_selector.value.split()[-1])
536+
self.controller.set_time(segment_index=segment_index)
536537
t_start, t_end = self.controller.get_t_start_t_stop()
537538
self.scatter_fig.x_range.start = t_start
538539
self.scatter_fig.x_range.end = t_end
@@ -555,7 +556,7 @@ def _on_panel_selection_geometry(self, event):
555556
return
556557

557558
# Append the current polygon to the lasso vertices if shift is held
558-
segment_index = self.segment_index
559+
segment_index = self.controller.get_time()[1]
559560
if self._lasso_vertices[segment_index] is None:
560561
self._lasso_vertices[segment_index] = []
561562
if len(selected) > self._current_selected:
@@ -582,7 +583,8 @@ def _panel_update_selected_spikes(self):
582583
selected_spike_indices = np.intersect1d(selected_spike_indices, self.plotted_inds)
583584
if len(selected_spike_indices) > 0:
584585
# map absolute indices to visible spikes
585-
sl = self.controller.segment_slices[self.segment_index]
586+
segment_index = self.controller.get_time()[1]
587+
sl = self.controller.segment_slices[segment_index]
586588
spikes_in_seg = self.controller.spikes[sl]
587589
visible_mask = np.zeros(len(spikes_in_seg), dtype=bool)
588590
for unit_index, unit_id in self.controller.iter_visible_units():
@@ -604,7 +606,8 @@ def _panel_on_spike_selection_changed(self):
604606
return
605607
elif len(selected_indices) == 1:
606608
selected_segment = self.controller.spikes[selected_indices[0]]['segment_index']
607-
if selected_segment != self.segment_index:
609+
segment_index = self.controller.get_time()[1]
610+
if selected_segment != segment_index:
608611
self.segment_selector.value = f"Segment {selected_segment}"
609612
self._panel_change_segment(None)
610613
# update selected spikes

spikeinterface_gui/controller.py

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -60,11 +60,8 @@ def __init__(self, analyzer=None, backend="qt", parent=None, verbose=False, save
6060
self.verbose = verbose
6161
t0 = time.perf_counter()
6262

63-
6463
self.main_settings = _default_main_settings.copy()
6564

66-
67-
6865
self.num_channels = self.analyzer.get_num_channels()
6966
# this now private and shoudl be acess using function
7067
self._visible_unit_ids = [self.unit_ids[0]]
@@ -421,19 +418,21 @@ def set_time(self, time=None, segment_index=None):
421418
def update_time_info(self):
422419
# set default time info
423420
if self.main_settings["use_times"] and self.analyzer.has_recording():
424-
self.time_info = dict(
425-
time_by_seg=np.array(
426-
[
427-
self.analyzer.recording.get_start_time(segment_index) for segment_index in range(self.num_segments)
428-
],
429-
dtype="float64"),
430-
segment_index=0
421+
time_by_seg=np.array(
422+
[
423+
self.analyzer.recording.get_start_time(segment_index) for segment_index in range(self.num_segments)
424+
],
425+
dtype="float64"
431426
)
432427
else:
428+
time_by_seg=np.array([0] * self.num_segments, dtype="float64")
429+
if not hasattr(self, 'time_info'):
433430
self.time_info = dict(
434-
time_by_seg=np.array([0] * self.num_segments, dtype="float64"),
431+
time_by_seg=time_by_seg,
435432
segment_index=0
436433
)
434+
else:
435+
self.time_info['time_by_seg'] = time_by_seg
437436

438437
def get_t_start_t_stop(self):
439438
segment_index = self.time_info["segment_index"]

spikeinterface_gui/spikerateview.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -100,11 +100,11 @@ def _panel_make_layout(self):
100100
import bokeh.plotting as bpl
101101
from .utils_panel import _bg_color
102102

103-
self.segment_index = 0
103+
segment_index = self.controller.get_time()[1]
104104
self.segment_selector = pn.widgets.Select(
105105
name="",
106106
options=[f"Segment {i}" for i in range(self.controller.num_segments)],
107-
value=f"Segment {self.segment_index}",
107+
value=f"Segment {segment_index}",
108108
)
109109
self.segment_selector.param.watch(self._panel_change_segment, 'value')
110110

@@ -130,9 +130,9 @@ def _panel_refresh(self):
130130
from bokeh.models import Range1d
131131

132132
segment_index = self.controller.get_time()[1]
133-
if segment_index != self.segment_index:
134-
self.segment_index = segment_index
135-
self.segment_selector.value = f"Segment {self.segment_index}"
133+
segment_index_from_selector = self.segment_selector.options.index(self.segment_selector.value)
134+
if segment_index != segment_index_from_selector:
135+
self.segment_selector.value = f"Segment {segment_index}"
136136

137137
visible_unit_ids = self.controller.get_visible_unit_ids()
138138

@@ -169,8 +169,8 @@ def _panel_refresh(self):
169169
self.rate_fig.y_range = Range1d(start=0, end=max_count*1.2)
170170

171171
def _panel_change_segment(self, event):
172-
self.segment_index = int(self.segment_selector.value.split()[-1])
173-
self.controller.set_time(segment_index=self.segment_index)
172+
segment_index = int(self.segment_selector.value.split()[-1])
173+
self.controller.set_time(segment_index=segment_index)
174174
self.refresh()
175175
self.notify_time_info_updated()
176176

spikeinterface_gui/tracemapview.py

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -168,27 +168,27 @@ def _qt_on_time_info_updated(self):
168168
time, segment_index = self.controller.get_time()
169169
# Block auto refresh to avoid recursive calls
170170
self._block_auto_refresh_and_notify = True
171-
172171
self._qt_change_segment(segment_index)
173172
self.timeseeker.seek(time)
174-
175-
self._block_auto_refresh_and_notify = False
176-
# we need refresh in QT because changing tab/docking/undocking doesn't trigger a refresh
177173
self.refresh()
174+
self._block_auto_refresh_and_notify = False
178175

179176
def _qt_on_use_times_updated(self):
180-
# Update time seeker
177+
# Block auto refresh to avoid recursive calls
178+
self._block_auto_refresh_and_notify = True
181179
t_start, t_stop = self.controller.get_t_start_t_stop()
182180
self.timeseeker.set_start_stop(t_start, t_stop)
183181
self.timeseeker.seek(self.controller.get_time()[0])
182+
self.refresh()
183+
self._block_auto_refresh_and_notify = False
184184

185185
## Panel ##
186186
def _panel_make_layout(self):
187187
import panel as pn
188188
import bokeh.plotting as bpl
189189
from .utils_panel import _bg_color
190190
from bokeh.models import ColumnDataSource, LinearColorMapper, Range1d
191-
from bokeh.events import MouseWheel, Tap
191+
from bokeh.events import MouseWheel, DoubleTap
192192

193193

194194
# Create figure
@@ -203,7 +203,7 @@ def _panel_make_layout(self):
203203
self.figure.toolbar.logo = None
204204

205205
self.figure.on_event(MouseWheel, self._panel_gain_zoom)
206-
self.figure.on_event(Tap, self._panel_on_tap)
206+
self.figure.on_event(DoubleTap, self._panel_on_double_tap)
207207

208208
# Add selection line
209209
self.selection_line = self.figure.line(
@@ -302,16 +302,6 @@ def _panel_refresh(self):
302302
self.figure.x_range.end = t2
303303
self.figure.y_range.end = data_curves.shape[1]
304304

305-
# TODO: if from a different unit, change unit visibility
306-
def _panel_on_tap(self, event):
307-
seg_index = self.controller.get_time()[1]
308-
time = event.x
309-
ind_spike_nearest = find_nearest_spike(self.controller, time, seg_index)
310-
if ind_spike_nearest is not None:
311-
self.controller.set_indices_spike_selected([ind_spike_nearest])
312-
self._panel_seek_with_selected_spike()
313-
self.notify_spike_selection_changed()
314-
315305
def _panel_on_settings_changed(self):
316306
self.make_color_lut()
317307
self.refresh()
@@ -365,4 +355,5 @@ def _panel_on_use_times_updated(self):
365355
* **auto scale**: Automatically adjust the scale of the traces.
366356
* **time (s)**: Set the time point to display traces.
367357
* **mouse wheel**: change the scale of the traces.
358+
* **double click**: select the nearest spike and center the view on it.
368359
"""

spikeinterface_gui/traceview.py

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ def _qt_xsize_zoom(self, xmove):
210210
factor = xmove/100.
211211
newsize = self.xsize*(factor+1.)
212212
limits = self.spinbox_xsize.opts['bounds']
213-
if newsize>0. and newsize<limits[1]:
213+
if newsize > 0. and newsize < limits[1]:
214214
self.spinbox_xsize.setValue(newsize)
215215

216216
def _qt_on_scroll_time(self, val):
@@ -348,6 +348,14 @@ def _panel_seek_with_selected_spike(self):
348348
self.refresh()
349349
self.notify_time_info_updated()
350350

351+
def _panel_on_double_tap(self, event):
352+
time = event.x
353+
ind_spike_nearest = find_nearest_spike(self.controller, time, self.controller.get_time()[1])
354+
if ind_spike_nearest is not None:
355+
self.controller.set_indices_spike_selected([ind_spike_nearest])
356+
self._panel_seek_with_selected_spike()
357+
self.notify_spike_selection_changed()
358+
351359
# TODO: pan behavior like Qt?
352360
# def _panel_on_pan_start(self, event):
353361
# self.drag_state["x_start"] = event.x
@@ -535,24 +543,25 @@ def _qt_on_time_info_updated(self):
535543

536544
self._qt_change_segment(segment_index)
537545
self.timeseeker.seek(time)
538-
539-
self._block_auto_refresh_and_notify = False
540-
# we need refresh in QT because changing tab/docking/undocking doesn't trigger a refresh
541546
self.refresh()
547+
self._block_auto_refresh_and_notify = False
542548

543549
def _qt_on_use_times_updated(self):
544550
# Update time seeker
551+
self._block_auto_refresh_and_notify = True
545552
t_start, t_stop = self.controller.get_t_start_t_stop()
546553
self.timeseeker.set_start_stop(t_start, t_stop)
547554
self.timeseeker.seek(self.controller.get_time()[0])
555+
self.refresh()
556+
self._block_auto_refresh_and_notify = False
548557

549558
## panel ##
550559
def _panel_make_layout(self):
551560
import panel as pn
552561
import bokeh.plotting as bpl
553562
from .utils_panel import _bg_color
554563
from bokeh.models import ColumnDataSource, Range1d
555-
from bokeh.events import Tap, MouseWheel
564+
from bokeh.events import DoubleTap, MouseWheel
556565

557566
self.figure = bpl.figure(
558567
sizing_mode="stretch_both",
@@ -592,7 +601,7 @@ def _panel_make_layout(self):
592601
x="x", y="y", size=10, fill_color="color", fill_alpha=self.settings['alpha'], source=self.spike_source
593602
)
594603

595-
self.figure.on_event(Tap, self._panel_on_tap)
604+
self.figure.on_event(DoubleTap, self._panel_on_double_tap)
596605

597606
self._panel_create_toolbar()
598607

@@ -652,13 +661,6 @@ def _panel_refresh(self):
652661
self.figure.y_range.end = n - 0.5
653662

654663
# TODO: if from a different unit, change unit visibility
655-
def _panel_on_tap(self, event):
656-
time = event.x
657-
ind_spike_nearest = find_nearest_spike(self.controller, time, self.controller.get_time()[1])
658-
if ind_spike_nearest is not None:
659-
self.controller.set_indices_spike_selected([ind_spike_nearest])
660-
self._panel_seek_with_selected_spike()
661-
self.notify_spike_selection_changed()
662664

663665
def _panel_on_spike_selection_changed(self):
664666
self._panel_seek_with_selected_spike()
@@ -676,22 +678,22 @@ def _panel_auto_scale(self, event):
676678
def _panel_on_time_info_updated(self):
677679
# Update segment and time slider range
678680
time, segment_index = self.controller.get_time()
679-
self._block_auto_refresh = True
681+
self._block_auto_refresh_and_notify = True
680682
self._panel_change_segment(segment_index)
681683
# Update time slider value
682684
self.time_slider.value = time
683-
self._block_auto_refresh = False
684-
# we don't need a refresh in panel because changing tab triggers a refresh
685+
self.refresh()
686+
self._block_auto_refresh_and_notify = False
685687

686688
def _panel_on_use_times_updated(self):
687689
# Update time seeker
688690
t_start, t_stop = self.controller.get_t_start_t_stop()
691+
self._block_auto_refresh_and_notify = True
689692
self.time_slider.start = t_start
690693
self.time_slider.end = t_stop
691-
692-
# Optionally clamp the current value if out of range
693694
self.time_slider.value = self.controller.get_time()[0]
694695
self.refresh()
696+
self._block_auto_refresh_and_notify = False
695697

696698

697699

@@ -725,4 +727,5 @@ def find_nearest_spike(controller, x, segment_index, max_distance_samples=None):
725727
* **auto scale**: Automatically adjust the scale of the traces.
726728
* **time (s)**: Set the time point to display traces.
727729
* **mouse wheel**: change the scale of the traces.
730+
* **double click**: select the nearest spike and center the view on it.
728731
"""

0 commit comments

Comments
 (0)