From d76c420b98339720dc89a07b64e549760c90814d Mon Sep 17 00:00:00 2001 From: Johannes Herforth Date: Wed, 17 Sep 2025 12:20:22 +0200 Subject: [PATCH 1/3] ENH: adds annotation filtering to raw figures --- mne/io/base.py | 2 ++ mne/viz/_figure.py | 4 +++- mne/viz/raw.py | 2 ++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/mne/io/base.py b/mne/io/base.py index c5808726264..f599e88a00e 100644 --- a/mne/io/base.py +++ b/mne/io/base.py @@ -1911,6 +1911,7 @@ def plot( color=None, bad_color="lightgray", event_color="cyan", + annotation_regex=".*", scalings=None, remove_dc=True, order=None, @@ -1951,6 +1952,7 @@ def plot( color, bad_color, event_color, + annotation_regex, scalings, remove_dc, order, diff --git a/mne/viz/_figure.py b/mne/viz/_figure.py index 2872a7621e2..22943576736 100644 --- a/mne/viz/_figure.py +++ b/mne/viz/_figure.py @@ -4,6 +4,7 @@ # License: BSD-3-Clause # Copyright the MNE-Python contributors. +import re import importlib import inspect from abc import ABC, abstractmethod @@ -182,7 +183,8 @@ def _setup_annotation_colors(self): segment_colors[key] = next(color_cycle) self.mne.annotation_segment_colors = segment_colors # init a couple other annotation-related variables - self.mne.visible_annotations = {label: True for label in labels} + annot_regex = re.compile(self.mne.annotation_regex) + self.mne.visible_annotations = {l: True if annot_regex.match(l) else False for l in labels} self.mne.show_hide_annotation_checkboxes = None def _update_annotation_segments(self): diff --git a/mne/viz/raw.py b/mne/viz/raw.py index 1570d6c5390..e0aa92478ec 100644 --- a/mne/viz/raw.py +++ b/mne/viz/raw.py @@ -37,6 +37,7 @@ def plot_raw( color=None, bad_color="lightgray", event_color="cyan", + annotation_regex=".*", scalings=None, remove_dc=True, order=None, @@ -373,6 +374,7 @@ def plot_raw( event_times=event_times, event_nums=event_nums, event_id_rev=event_id_rev, + annotation_regex=annotation_regex, # preprocessing projs=projs, projs_on=projs_on, From 0f25754a7cf70108b393a99c400f2d65f6d2a495 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 17 Sep 2025 18:38:41 +0000 Subject: [PATCH 2/3] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- mne/viz/_figure.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/mne/viz/_figure.py b/mne/viz/_figure.py index 22943576736..6e08eb2a8ea 100644 --- a/mne/viz/_figure.py +++ b/mne/viz/_figure.py @@ -4,9 +4,9 @@ # License: BSD-3-Clause # Copyright the MNE-Python contributors. -import re import importlib import inspect +import re from abc import ABC, abstractmethod from collections import OrderedDict from contextlib import contextmanager @@ -184,7 +184,9 @@ def _setup_annotation_colors(self): self.mne.annotation_segment_colors = segment_colors # init a couple other annotation-related variables annot_regex = re.compile(self.mne.annotation_regex) - self.mne.visible_annotations = {l: True if annot_regex.match(l) else False for l in labels} + self.mne.visible_annotations = { + l: True if annot_regex.match(l) else False for l in labels + } self.mne.show_hide_annotation_checkboxes = None def _update_annotation_segments(self): From 3c747cebd14d40c46c6fd135d46eacb838a63cf6 Mon Sep 17 00:00:00 2001 From: Johannes Herforth Date: Wed, 17 Sep 2025 12:20:22 +0200 Subject: [PATCH 3/3] ENH: Add Tests and Documentation for annotation_regex parameter --- doc/changes/dev/13425.newfeature.rst | 1 + doc/changes/names.inc | 1 + mne/io/base.py | 36 ++++++++++++++-------------- mne/viz/_figure.py | 2 +- mne/viz/raw.py | 5 +++- mne/viz/tests/test_raw.py | 17 +++++++++++++ 6 files changed, 42 insertions(+), 20 deletions(-) create mode 100644 doc/changes/dev/13425.newfeature.rst diff --git a/doc/changes/dev/13425.newfeature.rst b/doc/changes/dev/13425.newfeature.rst new file mode 100644 index 00000000000..28aa6f4c27f --- /dev/null +++ b/doc/changes/dev/13425.newfeature.rst @@ -0,0 +1 @@ +Added `annotation_regex` parameter to :func:`mne.viz.raw.plot_raw`, automatically hiding annotations not matching the regex, by :newcontrib: `Johannes Herforth`_ diff --git a/doc/changes/names.inc b/doc/changes/names.inc index 754299f8575..82484fb5004 100644 --- a/doc/changes/names.inc +++ b/doc/changes/names.inc @@ -142,6 +142,7 @@ .. _jeythekey: https://github.com/jeythekey .. _Joan Massich: https://github.com/massich .. _Johann Benerradi: https://github.com/HanBnrd +.. _Johannes Herforth: https://github.com/DerAndereJohannes .. _Johannes Niediek: https://github.com/jniediek .. _John Samuelsson: https://github.com/johnsam7 .. _John Veillette: https://psychology.uchicago.edu/directory/john-veillette diff --git a/mne/io/base.py b/mne/io/base.py index f599e88a00e..29852d38863 100644 --- a/mne/io/base.py +++ b/mne/io/base.py @@ -1911,6 +1911,7 @@ def plot( color=None, bad_color="lightgray", event_color="cyan", + *, annotation_regex=".*", scalings=None, remove_dc=True, @@ -1935,7 +1936,6 @@ def plot( time_format="float", precompute=None, use_opengl=None, - *, picks=None, theme=None, overview_mode=None, @@ -1952,23 +1952,23 @@ def plot( color, bad_color, event_color, - annotation_regex, - scalings, - remove_dc, - order, - show_options, - title, - show, - block, - highpass, - lowpass, - filtorder, - clipping, - show_first_samp, - proj, - group_by, - butterfly, - decim, + annotation_regex=annotation_regex, + scalings=scalings, + remove_dc=remove_dc, + order=order, + show_options=show_options, + title=title, + show=show, + block=block, + highpass=highpass, + lowpass=lowpass, + filtorder=filtorder, + clipping=clipping, + show_first_samp=show_first_samp, + proj=proj, + group_by=group_by, + butterfly=butterfly, + decim=decim, noise_cov=noise_cov, event_id=event_id, show_scrollbars=show_scrollbars, diff --git a/mne/viz/_figure.py b/mne/viz/_figure.py index 6e08eb2a8ea..1c93a258dff 100644 --- a/mne/viz/_figure.py +++ b/mne/viz/_figure.py @@ -185,7 +185,7 @@ def _setup_annotation_colors(self): # init a couple other annotation-related variables annot_regex = re.compile(self.mne.annotation_regex) self.mne.visible_annotations = { - l: True if annot_regex.match(l) else False for l in labels + label: True if annot_regex.findall(label) else False for label in labels } self.mne.show_hide_annotation_checkboxes = None diff --git a/mne/viz/raw.py b/mne/viz/raw.py index e0aa92478ec..fe67fa6ddaa 100644 --- a/mne/viz/raw.py +++ b/mne/viz/raw.py @@ -37,6 +37,7 @@ def plot_raw( color=None, bad_color="lightgray", event_color="cyan", + *, annotation_regex=".*", scalings=None, remove_dc=True, @@ -62,7 +63,6 @@ def plot_raw( precompute=None, use_opengl=None, picks=None, - *, theme=None, overview_mode=None, splash=True, @@ -100,6 +100,9 @@ def plot_raw( Color to make bad channels. %(event_color)s Defaults to ``'cyan'``. + annotation_regex : str + A regex pattern applied to each annotation's label. + Matching labels remain visible, non-matching labels are hidden. %(scalings)s remove_dc : bool If True remove DC component when plotting data. diff --git a/mne/viz/tests/test_raw.py b/mne/viz/tests/test_raw.py index c7dae919fbc..3c6c74c93d6 100644 --- a/mne/viz/tests/test_raw.py +++ b/mne/viz/tests/test_raw.py @@ -803,6 +803,23 @@ def test_plot_annotations(raw, browser_backend): fig._toggle_single_channel_annotation(ch_pick, 0) assert fig.mne.inst.annotations.ch_names[0] == (ch_pick,) + # Check if annotation filtering works - All annotations + annot = Annotations([42, 50], [1, 1], ["test", "test2"], raw.info["meas_date"]) + with pytest.warns(RuntimeWarning, match="expanding outside"): + raw.set_annotations(annot) + + fig = raw.plot() + + assert fig.mne.visible_annotations["test"] and fig.mne.visible_annotations["test2"] + + # Check if annotation filtering works - filtering annotations + # This should only make test2 visible and hide test + fig = raw.plot(annotation_regex="2$") + + assert ( + not fig.mne.visible_annotations["test"] and fig.mne.visible_annotations["test2"] + ) + @pytest.mark.parametrize("active_annot_idx", (0, 1, 2)) def test_overlapping_annotation_deletion(raw, browser_backend, active_annot_idx):