Mnz.viz.plot_raw becomes non-interactive in PyQt5 GUI

Hi, recently I was trying to embed the interactive figure gotten from mne.viz.plot_raw in a PyQt5 GUI, which I have asked before, but it became non-interactive. I tried to embed an interactive matplotlib.figure.Figure instance to do the same thing and it worked. Here is the code:

import matplotlib
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolbar
# from matplotlib.backends.qt_compat import QtCore
from PyQt5 import QtCore
from matplotlib.figure import Figure
from PyQt5 import QtWidgets
import sys
import numpy as np
class My_Main_window(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super(My_Main_window, self).__init__(parent)

        self.canvas = FigureCanvas(Figure(constrained_layout=True))
        self.canvas.draw()
        self.ax = self.canvas.figure.add_subplot()


        self.con_1 = np.random.random((30, 40, 10))
        self.num = 0
        con_plot = self.con_1[:, :, self.num]
        self.im = self.ax.matshow(con_plot)
        self.ax.set_title(self.num)
        self.canvas.figure.colorbar(self.im)
        self.canvas.mpl_connect('key_press_event', self.on_move)
        self.canvas.mpl_connect(
            "button_press_event", lambda *args, **kwargs: print(args, kwargs)
        )
        self.canvas.mpl_connect(
            "key_press_event", lambda *args, **kwargs: print(args, kwargs)
        )

        self.setCentralWidget(self.canvas)

        # Give the keyboard focus to the figure instead of the manager:
        # StrongFocus accepts both tab and click to focus and will enable the
        # canvas to process event without clicking.
        # https://doc.qt.io/qt-5/qt.html#FocusPolicy-enum
        self.canvas.setFocusPolicy(QtCore.Qt.StrongFocus)
        self.canvas.setFocus()
        print(type(self.canvas))

    def on_move(self, event):
        print(f"activate this {event.key}, {self.num}")
        if event.key == "left":
            if self.num == 0:
                self.num = 0
                con_plot = self.con_1[:, :, self.num]
            else:
                self.num -= 1
                con_plot = self.con_1[:, :, self.num]
        elif event.key == "right":
            if self.num == self.con_1.shape[2] - 1:
                self.num = 0
                con_plot = self.con_1[:, :, self.num]
            else:
                self.num += 1
                con_plot = self.con_1[:, :, self.num]
        else:
            con_plot = self.con_1[:, :, self.num]
        # update the image in place
        self.im.set_data(con_plot)
        self.ax.set_title(self.num)
        # tell Qt that the widget needs to be re-repainted
        self.canvas.draw_idle()

if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    app.setApplicationName("Plot")
    main_win = My_Main_window()
    main_win.show()
    app.exec()import matplotlib
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolbar
# from matplotlib.backends.qt_compat import QtCore
from PyQt5 import QtCore
from matplotlib.figure import Figure
from PyQt5 import QtWidgets
import sys
import numpy as np
class My_Main_window(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super(My_Main_window, self).__init__(parent)

        self.canvas = FigureCanvas(Figure(constrained_layout=True))
        self.canvas.draw()
        self.ax = self.canvas.figure.add_subplot()


        self.con_1 = np.random.random((30, 40, 10))
        self.num = 0
        con_plot = self.con_1[:, :, self.num]
        self.im = self.ax.matshow(con_plot)
        self.ax.set_title(self.num)
        self.canvas.figure.colorbar(self.im)
        self.canvas.mpl_connect('key_press_event', self.on_move)
        self.canvas.mpl_connect(
            "button_press_event", lambda *args, **kwargs: print(args, kwargs)
        )
        self.canvas.mpl_connect(
            "key_press_event", lambda *args, **kwargs: print(args, kwargs)
        )

        self.setCentralWidget(self.canvas)

        # Give the keyboard focus to the figure instead of the manager:
        # StrongFocus accepts both tab and click to focus and will enable the
        # canvas to process event without clicking.
        # https://doc.qt.io/qt-5/qt.html#FocusPolicy-enum
        self.canvas.setFocusPolicy(QtCore.Qt.StrongFocus)
        self.canvas.setFocus()
        print(type(self.canvas))

    def on_move(self, event):
        print(f"activate this {event.key}, {self.num}")
        if event.key == "left":
            if self.num == 0:
                self.num = 0
                con_plot = self.con_1[:, :, self.num]
            else:
                self.num -= 1
                con_plot = self.con_1[:, :, self.num]
        elif event.key == "right":
            if self.num == self.con_1.shape[2] - 1:
                self.num = 0
                con_plot = self.con_1[:, :, self.num]
            else:
                self.num += 1
                con_plot = self.con_1[:, :, self.num]
        else:
            con_plot = self.con_1[:, :, self.num]
        # update the image in place
        self.im.set_data(con_plot)
        self.ax.set_title(self.num)
        # tell Qt that the widget needs to be re-repainted
        self.canvas.draw_idle()

if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    app.setApplicationName("Plot")
    main_win = My_Main_window()
    main_win.show()
    app.exec()

This codes is to change different figures using the keyboard. These two lines of codes are the key to implement this:

self.canvas.setFocusPolicy(QtCore.Qt.StrongFocus)
self.canvas.setFocus()

So I did this:

import matplotlib
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.qt_compat import QtCore
from PyQt5 import QtWidgets
import sys
from mne.datasets import sample
import mne

class My_Main_window(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super(My_Main_window, self).__init__(parent)

        data_path = sample.data_path()
        fpath= data_path + '/MEG/sample/sample_audvis_raw.fif'
        self.data = mne.read_epochs(fpath, preload=True)
        self.fig = mne.viz.plot_epochs(self.data, title='1', show=False)
        self.canvas = FigureCanvas(self.fig)
        self.canvas.draw()
        self.stack = QtWidgets.QStackedWidget()
        self.stack.addWidget(self.canvas)
        self.setCentralWidget(self.stack)

        # Give the keyboard focus to the figure instead of the manager:
        # StrongFocus accepts both tab and click to focus and will enable the
        # canvas to process event without clicking.
        # https://doc.qt.io/qt-5/qt.html#FocusPolicy-enum
        self.canvas.setFocusPolicy(QtCore.Qt.StrongFocus | QtCore.Qt.WheelFocus)
        self.canvas.setFocus()


if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    app.setApplicationName("Plot")
    main_win = My_Main_window()
    main_win.show()
    app.exec()

While it is still non-interactive, which bothers me now.

Hello @BarryLiu97, thanks for reaching out. Are you using MNE-Python 0.22? Lots has changed in terms of plotting there. @drammock would be the wizard 🪄 to know about this stuff – not sure if he’s currently available though!

Yes, I am using 0.22.0

Has this been solved? I’m looking to do something similar but this concerns me. Could it be a threading issue?

Hi @Neurovella, I don’t know if @BarryLiu97 ever solved it, but I can add a couple comments. First, we haven’t done anything recently to MNE-Python to test or facilitate embedding raw plots within a user-created GUI. Second: recent versions of Matplotlib have a “subfigure” API, which might make it easier to embed the entire raw.plot() figure within your own GUI. See here:

https://matplotlib.org/stable/gallery/subplots_axes_and_figures/subfigures.html

@drammock Thank you for getting back, and for the resource. I will refer to the subfigure API if any trouble arises while implementing MNE’s figures into my GUI.

I appreciate you guys building such a useful package, MNE is such a huge help!

Hi, I’ve not solved it, for I’ve changed my plan of the software on visualization, but it is a good start now of this subfigure.

1 Like