From 11eabca15c103e5511da2be6cac25dd0cfd09724 Mon Sep 17 00:00:00 2001 From: Hansuja Date: Sun, 15 Mar 2026 21:58:25 +0530 Subject: [PATCH 1/9] ENH: add cmap parameter to Evoked.animate_topomap --- mne/evoked.py | 7 +++++++ mne/viz/tests/test_topomap.py | 25 +++++++++++++++++++++++++ mne/viz/topomap.py | 6 +++++- 3 files changed, 37 insertions(+), 1 deletion(-) diff --git a/mne/evoked.py b/mne/evoked.py index 32475b37818..cbf1a62a111 100644 --- a/mne/evoked.py +++ b/mne/evoked.py @@ -797,6 +797,7 @@ def plot_joint( def animate_topomap( self, ch_type=None, + cmap=None, times=None, frame_rate=None, butterfly=False, @@ -825,6 +826,11 @@ def animate_topomap( 'fnirs_fd_ac_amplitude', 'fnirs_fd_phase', and 'fnirs_od'. If None, first available channel type from the above list is used. Defaults to None. + cmap : str | Colormap | None + The colormap to use for plotting. If None, the colormap is chosen + based on the data values (see Notes). Defaults to None. + If the data contains only non-negative values, the "Reds" colormap + will be used. Otherwise, the "RdBu_r" colormap will be used. times : array of float | None The time points to plot. If None, 10 evenly spaced samples are calculated over the evoked time series. Defaults to None. @@ -882,6 +888,7 @@ def animate_topomap( vmin=vmin, vmax=vmax, verbose=verbose, + cmap=cmap, ) def as_type(self, ch_type="grad", mode="fast"): diff --git a/mne/viz/tests/test_topomap.py b/mne/viz/tests/test_topomap.py index 64a13b46006..67dc7ebc546 100644 --- a/mne/viz/tests/test_topomap.py +++ b/mne/viz/tests/test_topomap.py @@ -182,6 +182,31 @@ def test_plot_topomap_animation(capsys): out, _ = capsys.readouterr() assert "extrapolation mode local to 0" in out +def test_plot_topomap_animation_cmap(): + """Test animate_topomap with default and custom cmap.""" + evoked = read_evokeds(evoked_fname, "Left Auditory", baseline=(None, 0)) + + # default behaviour + fig_default, anim_default = evoked.animate_topomap( + ch_type="grad", + times=[0, 0.1], + butterfly=False, + time_unit="s", + ) + anim_default._func(1) + + # custom cmap behaviour + fig_cmap, anim_cmap = evoked.animate_topomap( + ch_type="grad", + times=[0, 0.1], + cmap="viridis", + butterfly=False, + time_unit="s", + ) + anim_cmap._func(1) + + # check cmap actually applied + assert fig_cmap.axes[0].images[0].get_cmap().name == "viridis" def test_plot_topomap_animation_csd(capsys): """Test topomap plotting of CSD data.""" diff --git a/mne/viz/topomap.py b/mne/viz/topomap.py index 1bd585bb4f1..8575e05971a 100644 --- a/mne/viz/topomap.py +++ b/mne/viz/topomap.py @@ -3149,6 +3149,7 @@ def _init_anim( merge_channels, sphere, ch_type, + cmap, image_interp, extrapolate, verbose, @@ -3174,7 +3175,8 @@ def _init_anim( data, _ = _merge_ch_data(data, "grad", []) norm = True if np.min(data) > 0 else False - cmap = "Reds" if norm else "RdBu_r" + if cmap is None: + cmap = "Reds" if norm else "RdBu_r" vmin, vmax = _setup_vmin_vmax(data, vmin, vmax, norm) @@ -3324,6 +3326,7 @@ def _key_press(event, params): def _topomap_animation( evoked, ch_type, + cmap, times, frame_rate, butterfly, @@ -3407,6 +3410,7 @@ def _topomap_animation( merge_channels=merge_channels, sphere=sphere, ch_type=ch_type, + cmap=cmap, image_interp=image_interp, extrapolate=extrapolate, verbose=verbose, From ec9810c1103ea2c1bcf648ce5f9f78e0f7339c73 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 15 Mar 2026 16:42:13 +0000 Subject: [PATCH 2/9] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- mne/viz/tests/test_topomap.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mne/viz/tests/test_topomap.py b/mne/viz/tests/test_topomap.py index 67dc7ebc546..33e7390666b 100644 --- a/mne/viz/tests/test_topomap.py +++ b/mne/viz/tests/test_topomap.py @@ -182,6 +182,7 @@ def test_plot_topomap_animation(capsys): out, _ = capsys.readouterr() assert "extrapolation mode local to 0" in out + def test_plot_topomap_animation_cmap(): """Test animate_topomap with default and custom cmap.""" evoked = read_evokeds(evoked_fname, "Left Auditory", baseline=(None, 0)) @@ -208,6 +209,7 @@ def test_plot_topomap_animation_cmap(): # check cmap actually applied assert fig_cmap.axes[0].images[0].get_cmap().name == "viridis" + def test_plot_topomap_animation_csd(capsys): """Test topomap plotting of CSD data.""" # evoked From 443990fb8856548f7604ac7c0853f5e33616ca9e Mon Sep 17 00:00:00 2001 From: Hansuja Date: Mon, 16 Mar 2026 14:13:18 +0530 Subject: [PATCH 3/9] test: add assertion for default cmap behavior in animate_topomap test --- mne/viz/tests/test_topomap.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mne/viz/tests/test_topomap.py b/mne/viz/tests/test_topomap.py index 67dc7ebc546..8e9aeeecc80 100644 --- a/mne/viz/tests/test_topomap.py +++ b/mne/viz/tests/test_topomap.py @@ -195,6 +195,10 @@ def test_plot_topomap_animation_cmap(): ) anim_default._func(1) + # default cmap check + default_cmap = fig_default.axes[0].images[0].get_cmap().name + assert default_cmap in ("RdBu_r", "Reds") + # custom cmap behaviour fig_cmap, anim_cmap = evoked.animate_topomap( ch_type="grad", From eb8913406b33e9e539643d2bc43feb51159df7a9 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 16 Mar 2026 08:47:34 +0000 Subject: [PATCH 4/9] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- mne/viz/tests/test_topomap.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mne/viz/tests/test_topomap.py b/mne/viz/tests/test_topomap.py index a6132faa9f9..84562cde7e7 100644 --- a/mne/viz/tests/test_topomap.py +++ b/mne/viz/tests/test_topomap.py @@ -199,7 +199,7 @@ def test_plot_topomap_animation_cmap(): # default cmap check default_cmap = fig_default.axes[0].images[0].get_cmap().name assert default_cmap in ("RdBu_r", "Reds") - + # custom cmap behaviour fig_cmap, anim_cmap = evoked.animate_topomap( ch_type="grad", From b94f1db1a894e8d46d535f60f494cc6791e468a3 Mon Sep 17 00:00:00 2001 From: Hansuja Date: Tue, 17 Mar 2026 01:43:33 +0530 Subject: [PATCH 5/9] API: make cmap keyword-only in Evoked.animate_topomap for backward compatibility and update test --- mne/evoked.py | 16 +++++++++------- mne/viz/tests/test_topomap.py | 36 +++-------------------------------- 2 files changed, 12 insertions(+), 40 deletions(-) diff --git a/mne/evoked.py b/mne/evoked.py index cbf1a62a111..cec9d6b5154 100644 --- a/mne/evoked.py +++ b/mne/evoked.py @@ -797,15 +797,15 @@ def plot_joint( def animate_topomap( self, ch_type=None, - cmap=None, times=None, frame_rate=None, + *, + cmap=None, butterfly=False, blit=True, show=True, time_unit="s", sphere=None, - *, image_interp=_INTERPOLATION_DEFAULT, extrapolate=_EXTRAPOLATE_DEFAULT, vmin=None, @@ -826,17 +826,19 @@ def animate_topomap( 'fnirs_fd_ac_amplitude', 'fnirs_fd_phase', and 'fnirs_od'. If None, first available channel type from the above list is used. Defaults to None. - cmap : str | Colormap | None - The colormap to use for plotting. If None, the colormap is chosen - based on the data values (see Notes). Defaults to None. - If the data contains only non-negative values, the "Reds" colormap - will be used. Otherwise, the "RdBu_r" colormap will be used. times : array of float | None The time points to plot. If None, 10 evenly spaced samples are calculated over the evoked time series. Defaults to None. frame_rate : int | None Frame rate for the animation in Hz. If None, frame rate = sfreq / 10. Defaults to None. + cmap : str | Colormap | None + The colormap to use for plotting. If None, the colormap is chosen + based on the data values (see Notes). Defaults to None. + If the data contains only non-negative values, the "Reds" colormap + will be used. Otherwise, the "RdBu_r" colormap will be used. + + .. versionadded:: 1.12.0 butterfly : bool Whether to plot the data as butterfly plot under the topomap. Defaults to False. diff --git a/mne/viz/tests/test_topomap.py b/mne/viz/tests/test_topomap.py index 84562cde7e7..d72d5c8d46a 100644 --- a/mne/viz/tests/test_topomap.py +++ b/mne/viz/tests/test_topomap.py @@ -175,43 +175,13 @@ def test_plot_topomap_animation(capsys): evoked = read_evokeds(evoked_fname, "Left Auditory", baseline=(None, 0)) # Test animation - _, anim = evoked.animate_topomap( - ch_type="grad", times=[0, 0.1], butterfly=False, time_unit="s", verbose="debug" + fig, anim = evoked.animate_topomap( + ch_type="grad", times=[0, 0.1], cmap='viridis', butterfly=False, time_unit="s", verbose="debug" ) anim._func(1) # _animate has to be tested separately on 'Agg' backend. out, _ = capsys.readouterr() assert "extrapolation mode local to 0" in out - - -def test_plot_topomap_animation_cmap(): - """Test animate_topomap with default and custom cmap.""" - evoked = read_evokeds(evoked_fname, "Left Auditory", baseline=(None, 0)) - - # default behaviour - fig_default, anim_default = evoked.animate_topomap( - ch_type="grad", - times=[0, 0.1], - butterfly=False, - time_unit="s", - ) - anim_default._func(1) - - # default cmap check - default_cmap = fig_default.axes[0].images[0].get_cmap().name - assert default_cmap in ("RdBu_r", "Reds") - - # custom cmap behaviour - fig_cmap, anim_cmap = evoked.animate_topomap( - ch_type="grad", - times=[0, 0.1], - cmap="viridis", - butterfly=False, - time_unit="s", - ) - anim_cmap._func(1) - - # check cmap actually applied - assert fig_cmap.axes[0].images[0].get_cmap().name == "viridis" + assert fig.axes[0].images[0].get_cmap().name == "viridis" def test_plot_topomap_animation_csd(capsys): From de3f2d5faeb2d1287d49e786797df81759ae166f Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 16 Mar 2026 20:15:51 +0000 Subject: [PATCH 6/9] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- mne/viz/tests/test_topomap.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/mne/viz/tests/test_topomap.py b/mne/viz/tests/test_topomap.py index d72d5c8d46a..62c314f3603 100644 --- a/mne/viz/tests/test_topomap.py +++ b/mne/viz/tests/test_topomap.py @@ -176,7 +176,12 @@ def test_plot_topomap_animation(capsys): # Test animation fig, anim = evoked.animate_topomap( - ch_type="grad", times=[0, 0.1], cmap='viridis', butterfly=False, time_unit="s", verbose="debug" + ch_type="grad", + times=[0, 0.1], + cmap="viridis", + butterfly=False, + time_unit="s", + verbose="debug", ) anim._func(1) # _animate has to be tested separately on 'Agg' backend. out, _ = capsys.readouterr() From 0c913443370b54fc1784e0e46a1ac35eedd7973f Mon Sep 17 00:00:00 2001 From: Hansuja Date: Tue, 24 Mar 2026 19:43:42 +0530 Subject: [PATCH 7/9] DOC: add changelog entry --- doc/changes/dev/13756.newfeature.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 doc/changes/dev/13756.newfeature.rst diff --git a/doc/changes/dev/13756.newfeature.rst b/doc/changes/dev/13756.newfeature.rst new file mode 100644 index 00000000000..434e79908df --- /dev/null +++ b/doc/changes/dev/13756.newfeature.rst @@ -0,0 +1 @@ +Added ``cmap`` parameter to ``Evoked.animate_topomap`` to allow user-specified colormaps., by :newcontrib:`Hansuja Budhiraja`. \ No newline at end of file From 6eb79807442d5a205df01da16751aa565d2aad36 Mon Sep 17 00:00:00 2001 From: Hansuja Date: Tue, 24 Mar 2026 22:17:46 +0530 Subject: [PATCH 8/9] DOC: edited docstring for animate_topomap --- mne/evoked.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mne/evoked.py b/mne/evoked.py index 69363f34b1b..6495592167e 100644 --- a/mne/evoked.py +++ b/mne/evoked.py @@ -830,7 +830,7 @@ def animate_topomap( frame_rate : int | None Frame rate for the animation in Hz. If None, frame rate = sfreq / 10. Defaults to None. - cmap : str | Colormap | None + cmap : matplotlib colormap | None The colormap to use for plotting. If None, the colormap is chosen based on the data values (see Notes). Defaults to None. If the data contains only non-negative values, the "Reds" colormap From 5f69e781d37a37b14dcf7c5b30e6c2271e5364c6 Mon Sep 17 00:00:00 2001 From: Hansuja Date: Wed, 25 Mar 2026 00:30:59 +0530 Subject: [PATCH 9/9] DOC: edited docstring --- mne/evoked.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/mne/evoked.py b/mne/evoked.py index 6495592167e..2f953ff24a0 100644 --- a/mne/evoked.py +++ b/mne/evoked.py @@ -831,10 +831,8 @@ def animate_topomap( Frame rate for the animation in Hz. If None, frame rate = sfreq / 10. Defaults to None. cmap : matplotlib colormap | None - The colormap to use for plotting. If None, the colormap is chosen - based on the data values (see Notes). Defaults to None. - If the data contains only non-negative values, the "Reds" colormap - will be used. Otherwise, the "RdBu_r" colormap will be used. + Colormap to use. If None, 'Reds' is used for all positive data, + otherwise defaults to 'RdBu_r'. .. versionadded:: 1.12.0 butterfly : bool