diff --git a/doc/changes/dev/13989.bugfix.rst b/doc/changes/dev/13989.bugfix.rst new file mode 100644 index 00000000000..02368b6eecb --- /dev/null +++ b/doc/changes/dev/13989.bugfix.rst @@ -0,0 +1 @@ +Fix bug where :func:`mne.viz.plot_volume_source_estimates` with ``mode="glass_brain"`` always showed absolute values, by `Lau Møller Andersen`_. diff --git a/mne/viz/_3d.py b/mne/viz/_3d.py index 0ae551006c2..ccbfc174f7e 100644 --- a/mne/viz/_3d.py +++ b/mne/viz/_3d.py @@ -2723,6 +2723,9 @@ def _plot_and_correct(*, params, cut_coords): symmetric_cbar=True, title="", ) + if mode == "glass_brain": + # signed MIP (value with max abs) for diverging colormaps + plot_kwargs["plot_abs"] = not params["diverging"] params["axes"].clear() if params.get("fig_anat") is not None and plot_kwargs["colorbar"]: params["fig_anat"]._cbar.ax.clear() @@ -2776,8 +2779,14 @@ def plot_volume_source_estimates( If ``None``, ``stc.subject`` will be used. %(subjects_dir)s mode : ``'stat_map'`` | ``'glass_brain'`` - The plotting mode to use. For ``'glass_brain'``, activation absolute values are - displayed after being transformed to a standard MNI brain. + The plotting mode to use. For ``'glass_brain'``, activations are displayed + after being transformed to a standard MNI brain. With a diverging colormap + (e.g., ``clim=dict(pos_lims=...)``), the signed value with the maximum + absolute value along each projection is shown; otherwise, absolute values + are shown. + + .. versionchanged:: 1.13.1 + Signed values can be shown in ``'glass_brain'`` mode. bg_img : instance of SpatialImage | str The background image used in the nilearn plotting function. Can also be a string to use the ``bg_img`` file in the subject's @@ -2954,8 +2963,7 @@ def plot_volume_source_estimates( lx = ax_time.axvline(stc.times[time_idx], color="g") params.update(fig=fig, ax_time=ax_time, lx=lx, axes=axes) - allow_pos_lims = mode != "glass_brain" - mapdata = _process_clim(clim, colormap, transparent, stc.data, allow_pos_lims) + mapdata = _process_clim(clim, colormap, transparent, stc.data) _separate_map(mapdata) diverging = "pos_lims" in mapdata["clim"] ticks = _get_map_ticks(mapdata) @@ -2968,7 +2976,7 @@ def plot_volume_source_estimates( dup_neg = False if stc.data.min() < 0: ax_time.axhline(0.0, color="0.5", ls="-", lw=0.5, zorder=2) - dup_neg = not diverging # glass brain with signed data + dup_neg = not diverging # signed data with one-sided colormap yticks = list(ticks) if dup_neg: yticks += [0] + list(-np.array(ticks)) diff --git a/mne/viz/tests/test_3d_mpl.py b/mne/viz/tests/test_3d_mpl.py index eb71ecace6e..d52e867d44d 100644 --- a/mne/viz/tests/test_3d_mpl.py +++ b/mne/viz/tests/test_3d_mpl.py @@ -111,6 +111,36 @@ def test_plot_volume_source_estimates_basic( assert use_ax is not None label = use_ax.get_legend().get_texts()[0].get_text() assert re.match("[0-9]*", label) is not None, label + if mode != "glass_brain" or stype != "s": + return + + # signed data: diverging colormap (default) shows signed MIP, one-sided abs + stc.data -= 0.5 + for clim, signed in ( + ("auto", True), + (dict(kind="value", lims=[0.1, 0.2, 0.5]), False), + ): + with _record_warnings(): + fig = stc.plot( + sample_src, + subject="sample", + subjects_dir=subjects_dir, + mode=mode, + clim=clim, + ) + mips = [ + np.ma.asarray(im.get_array()) + for ax in fig.axes + for im in ax.images + if im.get_array().ndim == 2 + ] + assert len(mips) == 3 + for mip in mips: + assert mip.max() > 0.4 + if signed: + assert mip.min() < -0.4 + else: + assert mip.min() >= 0 @pytest.mark.slowtest # can be slow on OSX diff --git a/tutorials/inverse/50_beamformer_lcmv.py b/tutorials/inverse/50_beamformer_lcmv.py index 0add1434fd2..7da381dbf3a 100644 --- a/tutorials/inverse/50_beamformer_lcmv.py +++ b/tutorials/inverse/50_beamformer_lcmv.py @@ -252,7 +252,7 @@ # On MNI glass brain (orthoview; 2D) # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -stc.plot(mode="glass_brain", clim=dict(kind="value", lims=lims), **kwargs) +stc.plot(mode="glass_brain", clim=dict(kind="value", pos_lims=lims), **kwargs) # %% # Volumetric rendering (3D) with vectors