Skip to content

Commit b4decce

Browse files
Skip redrawing hscroll annotations when not needed (#13972)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent eb284ab commit b4decce

3 files changed

Lines changed: 28 additions & 21 deletions

File tree

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Skip replotting of annotations on the horizontal scrollbar in the matplotlib
2+
browser backend, resulting in a significant speedup for traces with a large
3+
number of annotations by `Frankie Robertson`_.

mne/viz/_figure.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -480,15 +480,15 @@ def _get_epoch_num_from_time(self, time):
480480
epoch_nums = self.mne.inst.selection
481481
return epoch_nums[np.searchsorted(self.mne.boundary_times[1:], time)]
482482

483-
def _redraw(self, update_data=True, annotations=False):
483+
def _redraw(self, update_data=True, annotations=False, *, skip_hscroll=False):
484484
"""Redraws backend if necessary."""
485485
if update_data:
486486
self._update_data()
487487

488488
self._draw_traces()
489489

490490
if annotations and not self.mne.is_epochs:
491-
self._draw_annotations()
491+
self._draw_annotations(skip_hscroll=skip_hscroll)
492492

493493
def _close(self, event=None):
494494
"""Handle close events (via keypress or window [x])."""

mne/viz/_mpl_figure.py

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -807,7 +807,7 @@ def _keypress(self, event):
807807
self.mne.ch_start = np.clip(ch_start, 0, ceiling)
808808
self._update_picks()
809809
self._update_vscroll()
810-
self._redraw()
810+
self._redraw(skip_hscroll=True)
811811
# scroll left/right
812812
elif key in ("right", "left", "shift+right", "shift+left"):
813813
old_t_start = self.mne.t_start
@@ -821,12 +821,12 @@ def _keypress(self, event):
821821
self.mne.t_start = np.clip(t_start, self.mne.first_time, t_max)
822822
if self.mne.t_start != old_t_start:
823823
self._update_hscroll()
824-
self._redraw(annotations=True)
824+
self._redraw(annotations=True, skip_hscroll=True)
825825
# scale traces
826826
elif key in ("=", "+", "-"):
827827
scaler = 1 / 1.1 if key == "-" else 1.1
828828
self.mne.scale_factor *= scaler
829-
self._redraw(update_data=False)
829+
self._redraw(update_data=False, skip_hscroll=True)
830830
# change number of visible channels
831831
elif (
832832
key in ("pageup", "pagedown")
@@ -844,7 +844,7 @@ def _keypress(self, event):
844844
if self.mne.n_channels != n_channels:
845845
self._update_picks()
846846
self._update_trace_offsets()
847-
self._redraw(annotations=True)
847+
self._redraw(annotations=True, skip_hscroll=True)
848848
# change duration
849849
elif key in ("home", "end"):
850850
old_dur = self.mne.duration
@@ -868,7 +868,7 @@ def _keypress(self, event):
868868
if self.mne.t_start + self.mne.duration > last_time:
869869
self.mne.t_start = last_time - self.mne.duration
870870
self._update_hscroll()
871-
self._redraw(annotations=True)
871+
self._redraw(annotations=True, skip_hscroll=True)
872872
elif key == "?": # help window
873873
self._toggle_help_fig(event)
874874
elif key == "a": # annotation mode
@@ -877,7 +877,7 @@ def _keypress(self, event):
877877
self._toggle_butterfly()
878878
elif key == "d": # DC shift
879879
self.mne.remove_dc = not self.mne.remove_dc
880-
self._redraw()
880+
self._redraw(skip_hscroll=True)
881881
elif key == "h": # histogram
882882
self._toggle_epoch_histogram()
883883
elif key == "j" and len(self.mne.projs): # SSP window
@@ -938,12 +938,12 @@ def _buttonpress(self, event):
938938
self._change_selection_vscroll(event)
939939
else:
940940
if self._check_update_vscroll_clicked(event):
941-
self._redraw()
941+
self._redraw(skip_hscroll=True)
942942
self.mne.vscroll_drag_offset = event.ydata - self.mne.ch_start
943943
# click in horizontal scrollbar
944944
elif event.inaxes == self.mne.ax_hscroll:
945945
if self._check_update_hscroll_clicked(event):
946-
self._redraw(annotations=True)
946+
self._redraw(annotations=True, skip_hscroll=True)
947947
self.mne.hscroll_drag_offset = event.xdata - self.mne.t_start
948948
# click on proj button
949949
elif event.inaxes == self.mne.ax_proj:
@@ -1606,21 +1606,22 @@ def _modify_annotation(self, old_x, new_x):
16061606
self._remove_annotation_hover_line()
16071607
self.canvas.draw_idle()
16081608

1609-
def _clear_annotations(self):
1609+
def _clear_annotations(self, *, skip_hscroll=False):
16101610
"""Clear all annotations from the figure."""
16111611
for annot in list(self.mne.annotations):
16121612
annot.remove()
16131613
self.mne.annotations.remove(annot)
1614-
for annot in list(self.mne.hscroll_annotations):
1615-
annot.remove()
1616-
self.mne.hscroll_annotations.remove(annot)
1614+
if not skip_hscroll:
1615+
for annot in list(self.mne.hscroll_annotations):
1616+
annot.remove()
1617+
self.mne.hscroll_annotations.remove(annot)
16171618
for text in list(self.mne.annotation_texts):
16181619
text.remove()
16191620
self.mne.annotation_texts.remove(text)
16201621

1621-
def _draw_annotations(self):
1622+
def _draw_annotations(self, *, skip_hscroll=False):
16221623
"""Draw (or redraw) the annotation spans."""
1623-
self._clear_annotations()
1624+
self._clear_annotations(skip_hscroll=skip_hscroll)
16241625
self._update_annotation_segments()
16251626
segments = self.mne.annotation_segments
16261627
onscreen_annotations = np.zeros(len(segments), dtype=bool)
@@ -1633,9 +1634,12 @@ def _draw_annotations(self):
16331634
zorder = self.mne.zorder["ann"] + idx
16341635
kwargs = dict(color=segment_color, alpha=0.3, zorder=zorder)
16351636
if self.mne.visible_annotations[descr]:
1636-
# draw all segments on ax_hscroll
1637-
annot = self.mne.ax_hscroll.fill_betweenx((0, 1), start, end, **kwargs)
1638-
self.mne.hscroll_annotations.append(annot)
1637+
if not skip_hscroll:
1638+
# draw all segments on ax_hscroll
1639+
annot = self.mne.ax_hscroll.fill_betweenx(
1640+
(0, 1), start, end, **kwargs
1641+
)
1642+
self.mne.hscroll_annotations.append(annot)
16391643
# draw only visible segments on ax_main
16401644
visible_segment = np.clip([start, end], times[0], times[-1])
16411645
if np.diff(visible_segment) > 0:
@@ -2408,9 +2412,9 @@ def _draw_traces(self):
24082412
if self.mne.event_times is not None:
24092413
self._draw_event_lines()
24102414

2411-
def _redraw(self, update_data=True, annotations=False):
2415+
def _redraw(self, update_data=True, annotations=False, *, skip_hscroll=False):
24122416
"""Redraw (convenience method for frequently grouped actions)."""
2413-
super()._redraw(update_data, annotations)
2417+
super()._redraw(update_data, annotations, skip_hscroll=skip_hscroll)
24142418
if self.mne.vline_visible and self.mne.is_epochs:
24152419
# prevent flickering
24162420
_ = self._recompute_epochs_vlines(None)

0 commit comments

Comments
 (0)