Semi-interactive plot() with matplotlib backend

I have a script that I run in terminal using python -i test_epoch_plot.py that implements the function epoch.plot(). The interactive plot appears, but any time I interact with it, I have to return to terminal, hit Enter in order for any clicks or button presses in the plot to take effect, even resizing the window by dragging the edges.

Has anyone else had this issue and know how to make it interactive in real-time?

  • MNE version: 1.0.3
  • operating system: macOS Monterey 12.3.1
  • matplotlib version: 3.5.2

Thanks for the help!

Hello @jadrew43 and welcome to the forum!

May I ask how you installed MNE — using one of our installers? Or by following our instructions for a manual install via conda?

Have you tried enforcing use of the Qt5 Matplotlib backend?

Insert the following at the very top of your script:

import matplotlib
matplotlib.use(“Qt5Agg”)

(I unfortunately cannot type the “correct” quotation marks on my current device, you’ll have to replace those in the snippet above)

Also could you please share the output of

import mne
mne.sys_info()

Thanks!

1 Like

Thanks @richard that worked! So this is using the Qt5 version of matplotlib’s graphic’s library?

In case you’re still interested, MNE was installed via conda and I had the following output:

mne.sys_info()

Platform:         macOS-12.3.1-x86_64-i386-64bit
Python:           3.9.12 | packaged by conda-forge | (main, Mar 24 2022, 23:23:20)  [Clang 12.0.1 ]
Executable:       /opt/anaconda3/envs/mnedev/bin/python3.9
CPU:              i386: 10 cores
Memory:           16.0 GB

mne:              1.1.dev0
numpy:            1.22.4 {blas=NO_ATLAS_INFO, lapack=lapack}
scipy:            1.8.1
matplotlib:       3.5.2 {backend=module://matplotlib_inline.backend_inline}

sklearn:          1.1.1
numba:            0.53.1
nibabel:          3.2.2
nilearn:          0.9.1
dipy:             1.5.0
cupy:             Not found
pandas:           1.4.2
pyvista:          0.34.0 {OpenGL 4.1 Metal - 76.3 via Apple M1 Pro}
pyvistaqt:        0.9.0
ipyvtklink:       0.2.2
vtk:              9.1.0
qtpy:             2.1.0 {PyQt5=5.12.9}
ipympl:           Not found
pyqtgraph:        0.12.4
pooch:            v1.6.0

mne_bids:         0.11.dev0
mne_nirs:         Not found
mne_features:     Not found
mne_qt_browser:   0.4.dev0
mne_connectivity: 0.4dev0
mne_icalabel:     Not found
1 Like

Yes, it’s explicitly requesting the Qt5-based backend.

We should probably update the installers to make it such that this is always the case. I’ve opened an issue about this:

@drammock @cbrnr Would you have any idea as to why @jadrew43 was seeing this problem with the macosx backend in the first place?

The macosx backend works for me. I’d blame it on Anaconda, which does not play nicely with the macOS GUI (framework build and whatnot).

import mne
import numpy as np

epochs = mne.EpochsArray(
    data=np.random.rand(50, 16, 1000) * 1e-6,
    info=mne.create_info(16, 256, "eeg"),
)
epochs.plot()

For some reason, I have to call epochs.plot() twice though before the figure appears. In IPython, this can be solved by %matplotlib at the very beginning.

1 Like

I can replicate with an adjusted version of your code, that enforces use of the macosx backend and Matplotlib-based plotting:

import matplotlib
import mne
import numpy as np

matplotlib.use('macosx')


epochs = mne.EpochsArray(
    data=np.random.rand(50, 16, 1000) * 1e-6,
    info=mne.create_info(16, 256, "eeg"),
)

with mne.viz.use_browser_backend('matplotlib'):
    epochs.plot()

The plotting window never gets proper focus, which is one of those old “Qt in conda” problems, I believe?

I don’t have to call epochs.plot() twice, though.

I also installed python.app and tried to run via pythonw and python.app, same result.

Works fine without the -i switch, and instead using epochs.plot(block=True).

So I would almost say this is a bug in MNE…?

So this works:

import matplotlib
import mne
import numpy as np

matplotlib.use('macosx')


epochs = mne.EpochsArray(
    data=np.random.rand(50, 16, 1000) * 1e-6,
    info=mne.create_info(16, 256, "eeg"),
)

with mne.viz.use_browser_backend('matplotlib'):
    epochs.plot(block=True)

both when run via python and via python -i.

@marsipu @larsoner Any idea? I think this involves bits of code that were fairly recently touched when we switched to mne-qt-browser as the primary backend.

It could be a bug in MNE-Python, I have a hunch that we’re trying to do too much magic here. On my Mac, I do need to call epochs.plot() twice even when setting block=True. Calling matplotlib.pyplot.ion() also doesn’t help.

1 Like

This part confuses me; I’ve never seen the inline backend used outside of a notebook. Also I know almost nothing about macOS-specific problems (MPL or otherwise) since I don’t have regular access to a mac. I will say that I’ve recently dug into the backend-abstraction-layer code for raw/epochs/ICA plots, and I find it challenging to keep track of what’s going on; I’ve started a little clean-up in Fix orphaned annot window by drammock · Pull Request #10776 · mne-tools/mne-python · GitHub but there’s certainly room for improvement.

I assumed @jadrew43 was running this in an interactive environment, but I might be wrong.

Maybe, but

suggests otherwise

I suspect because of the OS that the MacOSX backend was being used in the original post, and it’s usually not very good/responsive. I’d expect that using Qt would fix the problem because of how they use inputhook/idle processing, and it seems like it indeed worked. So to me this is likely another instance of “tell people to use some variant of Qt rather than the MacOSX matplotlib backend”

1 Like

The next version of our standalone installers will default to QtAgg to avoid this kind of issue.