From fb9484e795ff9f2218cecf90026ce28379409ad8 Mon Sep 17 00:00:00 2001 From: CarinaFo Date: Sat, 20 Jun 2026 15:12:15 +1000 Subject: [PATCH 1/6] add new attribute to style mask labels (channel names) to plot_topomap --- mne/defaults.py | 4 ++++ mne/evoked.py | 2 ++ mne/utils/docs.py | 7 ++++++ mne/viz/topomap.py | 54 ++++++++++++++++++++++++++++++++++++++-------- 4 files changed, 58 insertions(+), 9 deletions(-) diff --git a/mne/defaults.py b/mne/defaults.py index 41fc8603778..2175abeeb74 100644 --- a/mne/defaults.py +++ b/mne/defaults.py @@ -252,6 +252,10 @@ markeredgewidth=1, markersize=4, ), + mask_label_params=dict( + fontsize="medium", # respects theme + fontweight="bold", + ), coreg=dict( mri_fid_opacity=1.0, dig_fid_opacity=1.0, diff --git a/mne/evoked.py b/mne/evoked.py index c1d62a1df52..15baf8e3feb 100644 --- a/mne/evoked.py +++ b/mne/evoked.py @@ -655,6 +655,7 @@ def plot_topomap( show_names=False, mask=None, mask_params=None, + mask_label_params=None, contours=6, outlines="head", sphere=None, @@ -697,6 +698,7 @@ def plot_topomap( show_names=show_names, mask=mask, mask_params=mask_params, + mask_label_params=mask_label_params, outlines=outlines, contours=contours, image_interp=image_interp, diff --git a/mne/utils/docs.py b/mne/utils/docs.py index 564bb4abb0d..2b4dc02c3a2 100644 --- a/mne/utils/docs.py +++ b/mne/utils/docs.py @@ -2580,6 +2580,13 @@ def _reflow_param_docstring(docstring, has_first_line=True, width=75): dict(marker='o', markerfacecolor='w', markeredgecolor='k', linewidth=0, markersize=4) """ +docdict["mask_label_params_topomap"] = """ +mask_label_params : dict | None + Additional plotting parameters for significant sensor labels. + Default (None) equals:: + + dict(fontsize='medium', fontweight='bold') +""" docdict["mask_patterns_topomap"] = _mask_base.format( shape="(n_channels, n_patterns)", shape_appendix="-pattern combinations", example="" ) diff --git a/mne/viz/topomap.py b/mne/viz/topomap.py index 1eb40d8d167..da8575d9a1c 100644 --- a/mne/viz/topomap.py +++ b/mne/viz/topomap.py @@ -1017,6 +1017,7 @@ def plot_topomap( names=None, mask=None, mask_params=None, + mask_label_params=None, contours=6, outlines="head", sphere=None, @@ -1049,6 +1050,9 @@ def plot_topomap( %(names_topomap)s %(mask_topomap)s %(mask_params_topomap)s + %(mask_label_params_topomap)s + + .. versionadded:: 1.13 %(contours_topomap)s %(outlines_topomap)s %(sphere_topomap_auto)s @@ -1117,6 +1121,7 @@ def plot_topomap( names=names, mask=mask, mask_params=mask_params, + mask_label_params=mask_label_params, outlines=outlines, contours=contours, image_interp=image_interp, @@ -1274,6 +1279,7 @@ def _plot_topomap( names=None, mask=None, mask_params=None, + mask_label_params=None, contours=6, outlines="head", sphere=None, @@ -1386,6 +1392,8 @@ def _plot_topomap( if "zorder" not in mask_params: mask_params["zorder"] = _TOPOMAP_ZORDER["sensors"] + mask_label_params = _handle_default("mask_label_params", mask_label_params) + # find mask limits and setup interpolation extent, Xi, Yi, interp = _setup_interp( pos, res, image_interp, extrapolate, outlines, border @@ -1467,15 +1475,36 @@ def _plot_topomap( _draw_outlines(axes, outlines) if names is not None and sensors: - for _pos, _name in zip(pos, names): - axes.text( - _pos[0], - _pos[1], - _name, - horizontalalignment="center", - verticalalignment="center", - size="x-small", - ) + if mask is None: + for _pos, _name in zip(pos, names): + axes.text( + _pos[0], + _pos[1], + _name, + horizontalalignment="center", + verticalalignment="center", + size="x-small", + ) + else: + for i, (_pos, _name) in enumerate(zip(pos, names)): + if mask[i]: + axes.text( + _pos[0], + _pos[1], + _name, + horizontalalignment="center", + verticalalignment="center", + **mask_label_params, + ) + else: + axes.text( + _pos[0], + _pos[1], + _name, + horizontalalignment="center", + verticalalignment="center", + size="x-small", + ) if onselect is not None: lim = axes.dataLim @@ -2125,6 +2154,7 @@ def plot_evoked_topomap( show_names=False, mask=None, mask_params=None, + mask_label_params=None, contours=6, outlines="head", sphere=None, @@ -2168,6 +2198,8 @@ def plot_evoked_topomap( %(show_names_topomap)s %(mask_evoked_topomap)s %(mask_params_topomap)s + mask_label_params : dict + put docstrings %(contours_topomap)s %(outlines_topomap)s %(sphere_topomap_auto)s @@ -2257,6 +2289,7 @@ def plot_evoked_topomap( show_names=show_names, mask=mask, mask_params=mask_params, + mask_label_params=mask_label_params, contours=contours, outlines=outlines, sphere=sphere, @@ -2297,6 +2330,7 @@ def _plot_evoked_topomap( show_names, mask, mask_params, + mask_label_params, contours, outlines, sphere, @@ -2339,6 +2373,7 @@ def _plot_evoked_topomap( del time_unit # mask_params defaults mask_params = _handle_default("mask_params", mask_params) + mask_label_params = _handle_default("mask_label_params", mask_label_params) mask_params["markersize"] *= size / 2.0 mask_params["markeredgewidth"] *= size / 2.0 # setup various parameters, and prepare outlines @@ -2529,6 +2564,7 @@ def _plot_evoked_topomap( cmap=cmap[0], cnorm=cnorm, mask_params=mask_params, + mask_label_params=mask_label_params, outlines=outlines, contours=contours, image_interp=image_interp, From d54977541c92feb6371dae60bb12117a464bfaab Mon Sep 17 00:00:00 2001 From: CarinaFo Date: Sun, 21 Jun 2026 10:11:26 +1000 Subject: [PATCH 2/6] fixed docstring warning --- mne/viz/topomap.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mne/viz/topomap.py b/mne/viz/topomap.py index da8575d9a1c..f13e0bb17d1 100644 --- a/mne/viz/topomap.py +++ b/mne/viz/topomap.py @@ -2198,8 +2198,7 @@ def plot_evoked_topomap( %(show_names_topomap)s %(mask_evoked_topomap)s %(mask_params_topomap)s - mask_label_params : dict - put docstrings + %(mask_label_params_topomap)s %(contours_topomap)s %(outlines_topomap)s %(sphere_topomap_auto)s From 79cbb1df145715f0eeda99018ec20e0d7d79eeb0 Mon Sep 17 00:00:00 2001 From: CarinaFo Date: Sun, 21 Jun 2026 10:33:15 +1000 Subject: [PATCH 3/6] add changelog entry --- doc/changes/dev/13969.newfeature.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 doc/changes/dev/13969.newfeature.rst diff --git a/doc/changes/dev/13969.newfeature.rst b/doc/changes/dev/13969.newfeature.rst new file mode 100644 index 00000000000..81c936c27a6 --- /dev/null +++ b/doc/changes/dev/13969.newfeature.rst @@ -0,0 +1 @@ +Add ``mask_label_params`` parameter to :func:`~mne.viz.plot_topomap` and :func:`~mne.viz.plot_evoked_topomap` to allow for customisation of masked channel labels, by `Carina Forster`_. \ No newline at end of file From 9c87b464e27b0adb7c20709ff0b8f694ad35d7d7 Mon Sep 17 00:00:00 2001 From: CarinaFo Date: Sat, 27 Jun 2026 15:19:46 +1000 Subject: [PATCH 4/6] add mask_label_params --- mne/evoked.py | 5 +++++ mne/preprocessing/_regress.py | 2 ++ mne/time_frequency/spectrum.py | 9 +++++++++ mne/time_frequency/tfr.py | 4 ++++ mne/utils/docs.py | 14 +++++++------- mne/viz/topomap.py | 29 +++++++++++++++++++++++++++++ 6 files changed, 56 insertions(+), 7 deletions(-) diff --git a/mne/evoked.py b/mne/evoked.py index 15baf8e3feb..50e4ff8cb46 100644 --- a/mne/evoked.py +++ b/mne/evoked.py @@ -806,6 +806,7 @@ def animate_topomap( show_names=False, mask=None, mask_params=None, + mask_label_params=None, contours=6, outlines="head", sphere=None, @@ -850,6 +851,9 @@ def animate_topomap( %(show_names_topomap)s %(mask_evoked_topomap)s %(mask_params_topomap)s + %(mask_label_params_topomap)s + + .. versionadded:: 1.13 %(contours_topomap)s %(outlines_topomap)s %(sphere_topomap_auto)s @@ -919,6 +923,7 @@ def animate_topomap( show_names=show_names, mask=mask, mask_params=mask_params, + mask_label_params=mask_label_params, contours=contours, outlines=outlines, sphere=sphere, diff --git a/mne/preprocessing/_regress.py b/mne/preprocessing/_regress.py index 6c866b6e421..cb5a1339aed 100644 --- a/mne/preprocessing/_regress.py +++ b/mne/preprocessing/_regress.py @@ -271,6 +271,7 @@ def plot( show_names=False, mask=None, mask_params=None, + mask_label_params=None, contours=6, outlines="head", sphere=None, @@ -295,6 +296,7 @@ def plot( show_names=show_names, mask=mask, mask_params=mask_params, + mask_label_params=mask_label_params, contours=contours, outlines=outlines, sphere=sphere, diff --git a/mne/time_frequency/spectrum.py b/mne/time_frequency/spectrum.py index 6591527a28b..dab12d02ee1 100644 --- a/mne/time_frequency/spectrum.py +++ b/mne/time_frequency/spectrum.py @@ -213,6 +213,7 @@ def plot_psd_topomap( show_names=False, mask=None, mask_params=None, + mask_label_params=None, contours=0, outlines="head", sphere=None, @@ -249,6 +250,9 @@ def plot_psd_topomap( %(show_names_topomap)s %(mask_evoked_topomap)s %(mask_params_topomap)s + %(mask_label_params_topomap)s + + .. versionadded:: 1.13 %(contours_topomap)s %(outlines_topomap)s %(sphere_topomap_auto)s @@ -789,6 +793,7 @@ def plot_topomap( show_names=False, mask=None, mask_params=None, + mask_label_params=None, contours=6, outlines="head", sphere=None, @@ -819,6 +824,9 @@ def plot_topomap( %(show_names_topomap)s %(mask_evoked_topomap)s %(mask_params_topomap)s + %(mask_label_params_topomap)s + + .. versionadded:: 1.13 %(contours_topomap)s %(outlines_topomap)s %(sphere_topomap_auto)s @@ -881,6 +889,7 @@ def plot_topomap( names=names, mask=mask, mask_params=mask_params, + mask_label_params=mask_label_params, contours=contours, outlines=outlines, sphere=sphere, diff --git a/mne/time_frequency/tfr.py b/mne/time_frequency/tfr.py index 24f13f925bf..dace3a5b14b 100644 --- a/mne/time_frequency/tfr.py +++ b/mne/time_frequency/tfr.py @@ -2613,6 +2613,7 @@ def plot_topomap( show_names=False, mask=None, mask_params=None, + mask_label_params=None, contours=6, outlines="head", sphere=None, @@ -2643,6 +2644,7 @@ def plot_topomap( show_names=show_names, mask=mask, mask_params=mask_params, + mask_label_params=mask_label_params, contours=contours, outlines=outlines, sphere=sphere, @@ -3589,6 +3591,7 @@ def plot_topomap( show_names=False, mask=None, mask_params=None, + mask_label_params=None, contours=6, outlines="head", sphere=None, @@ -3619,6 +3622,7 @@ def plot_topomap( show_names=show_names, mask=mask, mask_params=mask_params, + mask_label_params=mask_label_params, contours=contours, outlines=outlines, sphere=sphere, diff --git a/mne/utils/docs.py b/mne/utils/docs.py index 2b4dc02c3a2..4ab2354af58 100644 --- a/mne/utils/docs.py +++ b/mne/utils/docs.py @@ -2572,6 +2572,13 @@ def _reflow_param_docstring(docstring, has_first_line=True, width=75): example=" (useful for, e.g. marking which channels at which times a " "statistical test of the data reaches significance)", ) +docdict["mask_label_params_topomap"] = """ +mask_label_params : dict | None + Additional plotting parameters for significant sensor labels. + Default (None) equals:: + + dict(fontsize='medium', fontweight='bold') +""" docdict["mask_params_topomap"] = """ mask_params : dict | None Additional plotting parameters for plotting significant sensors. @@ -2580,13 +2587,6 @@ def _reflow_param_docstring(docstring, has_first_line=True, width=75): dict(marker='o', markerfacecolor='w', markeredgecolor='k', linewidth=0, markersize=4) """ -docdict["mask_label_params_topomap"] = """ -mask_label_params : dict | None - Additional plotting parameters for significant sensor labels. - Default (None) equals:: - - dict(fontsize='medium', fontweight='bold') -""" docdict["mask_patterns_topomap"] = _mask_base.format( shape="(n_channels, n_patterns)", shape_appendix="-pattern combinations", example="" ) diff --git a/mne/viz/topomap.py b/mne/viz/topomap.py index f13e0bb17d1..364eb45b1e4 100644 --- a/mne/viz/topomap.py +++ b/mne/viz/topomap.py @@ -1926,6 +1926,7 @@ def plot_tfr_topomap( show_names=False, mask=None, mask_params=None, + mask_label_params=None, contours=6, outlines="head", sphere=None, @@ -1976,6 +1977,9 @@ def plot_tfr_topomap( %(show_names_topomap)s %(mask_evoked_topomap)s %(mask_params_topomap)s + %(mask_label_params_topomap)s + + .. versionadded:: 1.13 %(contours_topomap)s %(outlines_topomap)s %(sphere_topomap_auto)s @@ -2102,6 +2106,7 @@ def plot_tfr_topomap( names=names, mask=mask, mask_params=mask_params, + mask_label_params=mask_label_params, contours=contours, outlines=outlines, sphere=sphere, @@ -2199,6 +2204,8 @@ def plot_evoked_topomap( %(mask_evoked_topomap)s %(mask_params_topomap)s %(mask_label_params_topomap)s + + .. versionadded:: 1.13 %(contours_topomap)s %(outlines_topomap)s %(sphere_topomap_auto)s @@ -2781,6 +2788,7 @@ def _plot_topomap_multi_cbar( names, mask, mask_params, + mask_label_params, contours, image_interp, extrapolate, @@ -2810,6 +2818,7 @@ def _plot_topomap_multi_cbar( names=names, mask=mask, mask_params=mask_params, + mask_label_params=mask_label_params, contours=contours, outlines=outlines, sphere=sphere, @@ -2855,6 +2864,7 @@ def plot_epochs_psd_topomap( names=None, mask=None, mask_params=None, + mask_label_params=None, contours=0, outlines="head", sphere=None, @@ -2901,6 +2911,8 @@ def plot_epochs_psd_topomap( %(names_topomap)s %(mask_evoked_topomap)s %(mask_params_topomap)s + + .. versionadded:: 1.13 %(contours_topomap)s %(outlines_topomap)s %(sphere_topomap_auto)s @@ -2966,6 +2978,7 @@ def plot_psds_topomap( names=None, mask=None, mask_params=None, + mask_label_params=None, contours=0, outlines="head", sphere=None, @@ -3001,6 +3014,9 @@ def plot_psds_topomap( %(names_topomap)s %(mask_evoked_topomap)s %(mask_params_topomap)s + %(mask_label_params_topomap)s + + .. versionadded:: 1.13 %(contours_topomap)s %(outlines_topomap)s %(sphere_topomap_auto)s @@ -3130,6 +3146,7 @@ def plot_psds_topomap( names=names, mask=mask, mask_params=mask_params, + mask_label_params=mask_label_params, contours=contours, image_interp=image_interp, extrapolate=extrapolate, @@ -3338,6 +3355,7 @@ def _topomap_animation( show_names, mask, mask_params, + mask_label_params, contours, outlines, sphere, @@ -3422,6 +3440,7 @@ def _topomap_animation( show_names=show_names, mask=mask, mask_params=mask_params, + mask_label_params=mask_label_params, contours=contours, outlines=outlines, sphere=sphere, @@ -3670,6 +3689,7 @@ def plot_arrowmap( show_names=False, mask=None, mask_params=None, + mask_label_params=None, outlines="head", contours=6, image_interp=_INTERPOLATION_DEFAULT, @@ -3716,6 +3736,9 @@ def plot_arrowmap( If ``True``, a list of names must be provided (see ``names`` keyword). %(mask_topomap)s %(mask_params_topomap)s + %(mask_label_params_topomap)s + + .. versionadded:: 1.13 %(outlines_topomap)s %(contours_topomap)s %(image_interp_topomap)s @@ -3810,6 +3833,7 @@ def plot_arrowmap( res=res, mask=mask, mask_params=mask_params, + mask_label_params=mask_label_params, outlines=outlines, contours=contours, image_interp=image_interp, @@ -4137,6 +4161,7 @@ def plot_regression_weights( show_names=False, mask=None, mask_params=None, + mask_label_params=None, contours=6, outlines="head", sphere=None, @@ -4165,6 +4190,9 @@ def plot_regression_weights( %(show_names_topomap)s %(mask_topomap)s %(mask_params_topomap)s + %(mask_label_params_topomap)s + + .. versionadded:: 1.13 %(contours_topomap)s %(outlines_topomap)s %(sphere_topomap_auto)s @@ -4279,6 +4307,7 @@ def plot_regression_weights( names=names, mask=mask, mask_params=mask_params, + mask_label_params=mask_label_params, contours=contours, image_interp=image_interp, extrapolate=extrapolate, From 0279a5ba7c4e2eecb7c5b71c4aba72d62adfcd1c Mon Sep 17 00:00:00 2001 From: CarinaFo Date: Sun, 28 Jun 2026 16:08:38 +1000 Subject: [PATCH 5/6] decoding add ons and fix bug in topomap --- mne/cov.py | 5 +++++ mne/decoding/csp.py | 10 ++++++++++ mne/decoding/spatial_filter.py | 12 ++++++++++++ mne/viz/topomap.py | 1 + 4 files changed, 28 insertions(+) diff --git a/mne/cov.py b/mne/cov.py index 1567b9b653b..70aaac3157f 100644 --- a/mne/cov.py +++ b/mne/cov.py @@ -327,6 +327,7 @@ def plot_topomap( show_names=False, mask=None, mask_params=None, + mask_label_params=None, contours=6, outlines="head", sphere=None, @@ -362,6 +363,9 @@ def plot_topomap( %(show_names_topomap)s %(mask_topomap)s %(mask_params_topomap)s + %(mask_label_params_topomap)s + + .. versionadded:: 1.13 %(contours_topomap)s %(outlines_topomap)s %(sphere_topomap_auto)s @@ -435,6 +439,7 @@ def plot_topomap( show_names=show_names, mask=mask, mask_params=mask_params, + mask_label_params=mask_label_params, outlines=outlines, contours=contours, image_interp=image_interp, diff --git a/mne/decoding/csp.py b/mne/decoding/csp.py index 56b66babaf7..18d8d5e0246 100644 --- a/mne/decoding/csp.py +++ b/mne/decoding/csp.py @@ -370,6 +370,7 @@ def plot_patterns( show_names=False, mask=None, mask_params=None, + mask_label_params=None, contours=6, outlines="head", sphere=None, @@ -409,6 +410,9 @@ def plot_patterns( %(show_names_topomap)s %(mask_patterns_topomap)s %(mask_params_topomap)s + %(mask_label_params_topomap)s + + .. versionadded:: 1.13 %(contours_topomap)s %(outlines_topomap)s %(sphere_topomap_auto)s @@ -453,6 +457,7 @@ def plot_patterns( show_names=show_names, mask=mask, mask_params=mask_params, + mask_label_params=mask_label_params, contours=contours, outlines=outlines, sphere=sphere, @@ -487,6 +492,7 @@ def plot_filters( show_names=False, mask=None, mask_params=None, + mask_label_params=None, contours=6, outlines="head", sphere=None, @@ -526,6 +532,9 @@ def plot_filters( %(show_names_topomap)s %(mask_patterns_topomap)s %(mask_params_topomap)s + %(mask_label_params_topomap)s + + .. versionadded:: 1.13 %(contours_topomap)s %(outlines_topomap)s %(sphere_topomap_auto)s @@ -570,6 +579,7 @@ def plot_filters( show_names=show_names, mask=mask, mask_params=mask_params, + mask_label_params=mask_label_params, contours=contours, outlines=outlines, sphere=sphere, diff --git a/mne/decoding/spatial_filter.py b/mne/decoding/spatial_filter.py index 169cca7d005..d679bf3cff9 100644 --- a/mne/decoding/spatial_filter.py +++ b/mne/decoding/spatial_filter.py @@ -26,6 +26,7 @@ def _plot_model( show_names=False, mask=None, mask_params=None, + mask_label_params=None, contours=6, outlines="head", sphere=None, @@ -63,6 +64,7 @@ def _plot_model( show_names=show_names, mask=mask, mask_params=mask_params, + mask_label_params=mask_label_params, contours=contours, outlines=outlines, sphere=sphere, @@ -394,6 +396,7 @@ def plot_filters( show_names=False, mask=None, mask_params=None, + mask_label_params=None, contours=6, outlines="head", sphere=None, @@ -433,6 +436,9 @@ def plot_filters( %(show_names_topomap)s %(mask_evoked_topomap)s %(mask_params_topomap)s + %(mask_label_params_topomap)s + + .. versionadded:: 1.13 %(contours_topomap)s %(outlines_topomap)s %(sphere_topomap_auto)s @@ -469,6 +475,7 @@ def plot_filters( show_names=show_names, mask=mask, mask_params=mask_params, + mask_label_params=mask_label_params, contours=contours, outlines=outlines, sphere=sphere, @@ -503,6 +510,7 @@ def plot_patterns( show_names=False, mask=None, mask_params=None, + mask_label_params=None, contours=6, outlines="head", sphere=None, @@ -542,6 +550,9 @@ def plot_patterns( %(show_names_topomap)s %(mask_evoked_topomap)s %(mask_params_topomap)s + %(mask_label_params_topomap)s + + .. versionadded:: 1.13 %(contours_topomap)s %(outlines_topomap)s %(sphere_topomap_auto)s @@ -578,6 +589,7 @@ def plot_patterns( show_names=show_names, mask=mask, mask_params=mask_params, + mask_label_params=mask_label_params, contours=contours, outlines=outlines, sphere=sphere, diff --git a/mne/viz/topomap.py b/mne/viz/topomap.py index 364eb45b1e4..03ccc0efe9b 100644 --- a/mne/viz/topomap.py +++ b/mne/viz/topomap.py @@ -2911,6 +2911,7 @@ def plot_epochs_psd_topomap( %(names_topomap)s %(mask_evoked_topomap)s %(mask_params_topomap)s + %(mask_label_params_topomap)s .. versionadded:: 1.13 %(contours_topomap)s From 9f99964b996568ff112f5b2867ba4eb8fb532d52 Mon Sep 17 00:00:00 2001 From: CarinaFo Date: Sat, 4 Jul 2026 14:22:32 +1000 Subject: [PATCH 6/6] added a test for mask_label_params --- mne/viz/tests/test_topomap.py | 89 ++++++++++++++++++++++++++++++++++- 1 file changed, 87 insertions(+), 2 deletions(-) diff --git a/mne/viz/tests/test_topomap.py b/mne/viz/tests/test_topomap.py index 21e6eaed72c..578f958b1ef 100644 --- a/mne/viz/tests/test_topomap.py +++ b/mne/viz/tests/test_topomap.py @@ -9,7 +9,7 @@ import matplotlib.pyplot as plt import numpy as np import pytest -from matplotlib.colors import PowerNorm, TwoSlopeNorm +from matplotlib.colors import PowerNorm, TwoSlopeNorm, to_rgba from matplotlib.patches import Circle from numpy.testing import assert_almost_equal, assert_array_equal, assert_equal @@ -1008,7 +1008,7 @@ def test_plot_ch_adjacency(): assert len(collections) == 2 # make sure the point is green - green = matplotlib.colors.to_rgba("tab:green") + green = to_rgba("tab:green") assert (collections[1].get_facecolor() == green).all() # make sure adjacency entry is modified after second click on another node @@ -1091,3 +1091,88 @@ def test_plot_topomap_info_names_ordering(ch_type): assert displayed_names == list(expected_names), ( f"Expected {list(expected_names)}, got {displayed_names}" ) + + +def test_plot_topomap_mask_label_params(): + """Test that mask_label_params styles the masked-sensor labels.""" + evoked = read_evokeds(evoked_fname)[0] + + significant = ( + "EEG 001", + "EEG 002", + "EEG 003", + "EEG 004", + "EEG 005", + "EEG 006", + "EEG 007", + "EEG 008", + ) + sig = np.isin(evoked.ch_names, significant) + mask = np.zeros(evoked.data.shape, dtype=bool) + mask[sig, :] = True + + # test non-default + mask_label_params = dict( + fontsize="medium", + color="green", + fontweight="bold", + bbox=dict(facecolor="red", alpha=0.3), + ) + + fig = evoked.plot_topomap( + times=0.1, + ch_type="eeg", + mask=mask, + show_names=True, + mask_label_params=mask_label_params, + show=False, + ) + + fig.canvas.draw() # important for the bbox patches + + sig_labels = [t for ax in fig.axes for t in ax.texts if t.get_text() in significant] + + assert sig_labels, "there are no masked-channel labels" + + # non masked channels should not be green + nonsig_labels = [ + t + for ax in fig.axes + for t in ax.texts + if t.get_text() in evoked.ch_names and t.get_text() not in significant + ] + + for ns in nonsig_labels: + assert to_rgba(ns.get_color()) != to_rgba("green") + + # loop over significant labels and check text attributes + for sl in sig_labels: + assert to_rgba(sl.get_color()) == to_rgba("green") + assert sl.get_fontweight() == "bold" + patch = sl.get_bbox_patch() + assert patch is not None + assert np.allclose(patch.get_facecolor()[:3], (1.0, 0.0, 0.0)) # red + + plt.close(fig) + + # test default mask labels + # should be dict(fontsize="medium", fontweight="bold") + fig = evoked.plot_topomap( + times=0.1, + ch_type="eeg", + mask=mask, + show_names=True, + mask_label_params=None, + show=False, + ) + + sig_labels = [t for ax in fig.axes for t in ax.texts if t.get_text() in significant] + + assert sig_labels, "there are no masked-channel labels" + + # masked labels should be bold and colored the same as unmasked labels + for sl in sig_labels: + assert sl.get_fontweight() == "bold" + assert to_rgba(sl.get_color()) == to_rgba(nonsig_labels[0].get_color()) + + plt.close(fig)