Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions doc/changes/dev/13795.other.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Made :meth:`evoked.plot() <mne.Evoked.plot>` instantiate ``MNELineFigure`` when it creates its own figure, aligning this path with the ongoing 2D plotting figure-class refactor discussed in :gh:`7751`, by `Pragnya Khandelwal`_.
17 changes: 15 additions & 2 deletions mne/viz/_mpl_figure.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
└ MNELineFigure Interactive figure for non-scrollable data.
Generated by:
- spectrum.plot()
- evoked.plot() TODO Not yet implemented
- evoked.plot()
- evoked.plot_white() TODO Not yet implemented
- evoked.plot_joint() TODO Not yet implemented
"""
Expand Down Expand Up @@ -2540,6 +2540,13 @@ def __init__(self, inst, n_axes, figsize, *, layout="constrained", **kwargs):
for ix in range(n_axes):
self.add_subplot(n_axes, 1, ix + 1)

def _keypress(self, event):
"""Handle keypress events, keeping default Matplotlib keybindings."""
from matplotlib.backend_bases import key_press_handler

super()._keypress(event)
key_press_handler(event, self.canvas, self.canvas.toolbar)


def _close_all():
"""Close all figures (only used in our tests)."""
Expand Down Expand Up @@ -2578,10 +2585,16 @@ def _line_figure(inst, axes=None, picks=None, **kwargs):
"""Instantiate a new line figure."""
from matplotlib.axes import Axes

from ..dipole import DipoleFixed

# if picks is None, only show data channels
allowed_ch_types = _DATA_CH_TYPES_SPLIT if picks is None else _VALID_CHANNEL_TYPES
# figure out expected number of axes
ch_types = np.array(inst.get_channel_types())
# DipoleFixed has no get_channel_types() of its own (no ContainsMixin)
if isinstance(inst, DipoleFixed):
ch_types = np.array(inst.info.get_channel_types())
else:
ch_types = np.array(inst.get_channel_types())
if picks is not None:
ch_types = ch_types[picks]
n_axes = len(np.intersect1d(ch_types, allowed_ch_types))
Expand Down
17 changes: 13 additions & 4 deletions mne/viz/evoked.py
Original file line number Diff line number Diff line change
Expand Up @@ -417,10 +417,19 @@ def _plot_evoked(

fig = None
if axes is None:
fig, axes = plt.subplots(len(ch_types_used), 1, layout="constrained")
if isinstance(axes, plt.Axes):
axes = [axes]
fig.set_size_inches(6.4, 2 + len(axes))
if plot_type == "butterfly":
from ._mpl_figure import _line_figure

fig, axes = _line_figure(
evoked,
picks=picks,
figsize=(6.4, 2 + len(ch_types_used)),
)
else:
fig, axes = plt.subplots(len(ch_types_used), 1, layout="constrained")
if isinstance(axes, plt.Axes):
axes = [axes]
fig.set_size_inches(6.4, 2 + len(axes))

if isinstance(axes, plt.Axes):
axes = [axes]
Expand Down
7 changes: 6 additions & 1 deletion mne/viz/tests/test_evoked.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
from mne.stats.parametric import _parametric_ci
from mne.utils import _record_warnings, catch_logging
from mne.viz import plot_compare_evokeds, plot_evoked_white, ui_events
from mne.viz.utils import _fake_click, _get_cmap
from mne.viz.utils import _fake_click, _fake_keypress, _get_cmap

base_dir = Path(__file__).parents[2] / "io" / "tests" / "data"
evoked_fname = base_dir / "test-ave.fif"
Expand Down Expand Up @@ -126,6 +126,7 @@ def test_plot_evoked():
fig = evoked.plot(
proj=True, hline=[1], exclude=[], window_title="foo", time_unit="s"
)
assert fig.__class__.__name__ == "MNELineFigure"
amplitudes = _get_amplitudes(fig)
assert len(amplitudes) == len(default_picks)
assert evoked.proj is False
Expand All @@ -140,6 +141,10 @@ def test_plot_evoked():
line = ax.lines[0]
_fake_click(fig, ax, [line.get_xdata()[0], line.get_ydata()[0]], "data")
_fake_click(fig, ax, [ax.get_xlim()[0], ax.get_ylim()[1]], "data")
# default Matplotlib keybindings (e.g. "q" to close) should still work
assert plt.fignum_exists(fig.number)
_fake_keypress(fig, "q")
assert not plt.fignum_exists(fig.number)
# plot with bad channels excluded & spatial_colors & zorder
evoked.plot(exclude="bads", time_unit="s")

Expand Down
2 changes: 1 addition & 1 deletion tutorials/evoked/10_evoked_overview.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@
#
# We can visualize the average evoked response for left-auditory stimuli using
# the :meth:`~mne.Evoked.plot` method, which yields a butterfly plot of each
# channel type:
# channel type (interactive butterfly figure):

evoked.plot()

Expand Down
Loading