Quantcast
Channel: Recent Questions - Stack Overflow
Viewing all articles
Browse latest Browse all 12141

Interactive checkboxes (or buttons) in subplots Matplotlib figure in QGraphicsView PyQt5

$
0
0

I'm trying to optimize example (https://matplotlib.org/stable/gallery/widgets/check_buttons.html) for my task in a small project.I have an example that works:

from PyQt5.QtWidgets import QApplicationimport numpy as npfrom matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvasfrom matplotlib.figure import Figurefrom matplotlib.widgets import CheckButtonsfrom ShortCircuitCalc.gui.windows import CustomGraphicView, MainWindowfrom PyQt5 import QtWidgetsclass Window(CustomGraphicView):    def __init__(self, parent=None):        super(Window, self).__init__(parent)        self.canvas = FigureCanvas(Figure(figsize=(5, 3)))        t = np.arange(0.0, 2.0, 0.01)        s0 = np.sin(2 * np.pi * t)        s1 = np.sin(4 * np.pi * t)        s2 = np.sin(6 * np.pi * t)        ax = self.canvas.figure.subplots()        l0, = ax.plot(t, s0, visible=False, lw=2, color="k", label="2 Hz")        l1, = ax.plot(t, s1, lw=2, color="r", label="4 Hz")        l2, = ax.plot(t, s2, lw=2, color="g", label="6 Hz")        self.canvas.figure.subplots_adjust(left=0.2)        self.lines = [l0, l1, l2]        rax = self.canvas.figure.add_axes([0.05, 0.4, 0.1, 0.15])        self.labels = [str(line.get_label()) for line in self.lines]        visibility = [line.get_visible() for line in self.lines]        self.check = CheckButtons(rax, self.labels, visibility)        self.check.on_clicked(self.is_click)    def is_click(self, label):        index = self.labels.index(label)        self.lines[index].set_visible(not self.lines[index].get_visible())        self.canvas.draw()def main():    import sys    app = QApplication(sys.argv)    w = MainWindow()    r = Window()    w.resultView.scene = QtWidgets.QGraphicsScene()    w.resultView.scene.addWidget(r.canvas)    w.resultView.setScene(w.resultView.scene)    w.show()    sys.exit(app.exec_())if __name__ == "__main__":    main()

I get correctly next working model:

Correctly one plot model

But I want to get such an active model for each subplot in my figure.I tried to rework the above example and even got the layout I needed, but the buttons on it are not interactive. How can I refine this to get each interactive subplot. At the moment I have this code and these results:

from PyQt5.QtWidgets import QApplicationimport numpy as npfrom matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvasfrom matplotlib.figure import Figurefrom matplotlib.widgets import CheckButtonsfrom ShortCircuitCalc.gui.windows import CustomGraphicView, MainWindowfrom PyQt5 import QtWidgetsclass Window(CustomGraphicView):    def __init__(self, parent=None):        super(Window, self).__init__(parent)        ncols = 5        nrows = 8        self.canvas = FigureCanvas(Figure(figsize=(ncols * 5, nrows * 3)))        t = np.arange(0.0, 2.0, 0.01)        s0 = np.sin(2 * np.pi * t)        s1 = np.sin(4 * np.pi * t)        s2 = np.sin(6 * np.pi * t)        ax = self.canvas.figure.subplots(ncols=ncols, nrows=nrows)        for col in range(ncols):            for row in range(nrows):                (l0,) = ax[row, col].plot(t, s0, visible=False, lw=2, color="k", label="2 Hz")                (l1,) = ax[row, col].plot(t, s1, lw=2, color="r", label="4 Hz")                (l2,) = ax[row, col].plot(t, s2, lw=2, color="g", label="6 Hz")                lines = [l0, l1, l2]                rax = ax[row, col].inset_axes([0.05, 0.4, 0.1, 0.15])                labels = [str(line.get_label()) for line in lines]                visibility = [line.get_visible() for line in lines]                self.check = CheckButtons(rax, labels, visibility)                self.check.on_clicked(self.is_click)        self.canvas.figure.subplots_adjust(left=0.2)    def is_click(self, label):        # index = self.labels.index(label)        # self.lines[index].set_visible(not self.lines[index].get_visible())        # self.canvas.draw()        print('Button is pressed')def main():    import sys    app = QApplication(sys.argv)    w = MainWindow()    r = Window()    w.resultView.scene = QtWidgets.QGraphicsScene()    w.resultView.scene.addWidget(r.canvas)    w.resultView.setScene(w.resultView.scene)    w.show()    sys.exit(app.exec_())if __name__ == "__main__":    main()

Uncorrect model with inactive buttons

In my code, CustomGraphicView is just a QGraphicsView with some navigation tweaks. At the moment the implementation of CustomGraphicView and its use cases are as follows:

import sysimport numpy as npimport matplotlibimport matplotlib.pyplot as pltfrom matplotlib.backends.backend_qt5agg import (    FigureCanvasQTAgg as FigCanvas,    NavigationToolbar2QT as NavToolbar,)from PyQt5 import QtWidgets, QtCore, QtGuiclass CustomGraphicView(QtWidgets.QGraphicsView):    def __init__(self,                 parent: QtWidgets = None,                 figure: matplotlib.figure.Figure = None,                 title: str = 'Viewer') -> None:        super(CustomGraphicView, self).__init__(parent)        self._title = title        self._figure = figure        self._scene = QtWidgets.QGraphicsScene()        if parent is not None:            self._canvas = None        else:            self._canvas = FigCanvas(self._figure)            self._scene.addWidget(self._canvas)        self.setScene(self._scene)        self.setWindowTitle(self._title)        self.setTransformationAnchor(QtWidgets.QGraphicsView.AnchorUnderMouse)        self.setResizeAnchor(QtWidgets.QGraphicsView.AnchorUnderMouse)        # Start viewing position        self.horizontalScrollBar().setSliderPosition(1)        self.verticalScrollBar().setSliderPosition(1)        self._zoom = 0        self._mousePressed = False        self._drag_pos = None        self.save_model_action = QtWidgets.QAction('Save model as ...', self)        self.save_model_action.triggered.connect(self.save_model)        self.save_fragment_action = QtWidgets.QAction('Save fragment as ...', self)        self.save_fragment_action.triggered.connect(self.save_fragment)    def set_figure(self, figure):        self._figure = figure        self._canvas = FigCanvas(self._figure)        self._scene.addWidget(self._canvas)        self.setScene(self._scene)    def mousePressEvent(self, event: QtCore.Qt.MouseButton.LeftButton) -> None:        if event.button() == QtCore.Qt.MouseButton.LeftButton:            self._mousePressed = True            self.viewport().setCursor(QtGui.QCursor(QtCore.Qt.CursorShape.OpenHandCursor))            self._drag_pos = event.pos()            event.accept()        else:            super(CustomGraphicView, self).mousePressEvent(event)    def mouseMoveEvent(self, event: QtCore.Qt.MouseButton.LeftButton) -> None:        if self._mousePressed:            new_pos = event.pos()            diff = new_pos - self._drag_pos            self._drag_pos = new_pos            self.horizontalScrollBar().setValue(self.horizontalScrollBar().value() - diff.x())            self.verticalScrollBar().setValue(self.verticalScrollBar().value() - diff.y())            self.viewport().setCursor(QtGui.QCursor(QtCore.Qt.CursorShape.OpenHandCursor))        else:            super(CustomGraphicView, self).mouseMoveEvent(event)    def mouseReleaseEvent(self, event: QtCore.Qt.MouseButton.LeftButton) -> None:        if event.button() == QtCore.Qt.MouseButton.LeftButton:            self._mousePressed = False            self.viewport().setCursor(QtGui.QCursor(QtCore.Qt.CursorShape.ArrowCursor))        super(CustomGraphicView, self).mouseReleaseEvent(event)    def wheelEvent(self, event: QtCore.Qt.KeyboardModifier.ControlModifier) -> None:        modifiers = QtWidgets.QApplication.keyboardModifiers()        if modifiers == QtCore.Qt.KeyboardModifier.ControlModifier:            if event.angleDelta().y() > 0:                factor = 1.25                self._zoom += 1            else:                factor = 0.8                self._zoom -= 1            if self._zoom > -1:                self.scale(factor, factor)            else:                self._zoom = 0        else:            super(CustomGraphicView, self).wheelEvent(event)    def contextMenuEvent(self, event: QtGui.QContextMenuEvent) -> None:        # Creating context menu        menu = QtWidgets.QMenu(self)        menu.addAction(self.save_model_action)        # Creating / adding separator        separator = QtWidgets.QAction(self)        separator.setSeparator(True)        menu.addAction(separator)        menu.addAction(self.save_fragment_action)        menu.exec(event.globalPos())    def save_model(self):        NavToolbar.save_figure(self._figure)    def save_fragment(self):        rect_region = QtCore.QRect(0, 0,                                   self.width() - self.verticalScrollBar().width(),                                   self.height() - self.horizontalScrollBar().height())        pixmap = self.grab(rect_region)        fname = QtWidgets.QFileDialog.getSaveFileName(self, 'Save fragment as ...', 'image.png','Portable Network Graphics (*.png);;''Joint Photographic Experts Group (*.jpeg *.jpg)')[0]        if fname:            pixmap.save(fname)if __name__ == '__main__':    # Some figure    fig, ax = plt.subplots()    t = np.arange(0.0, 2.0, 0.01)    s0 = np.sin(2 * np.pi * t)    s1 = np.sin(4 * np.pi * t)    s2 = np.sin(6 * np.pi * t)    ax.plot(t, s0, lw=2, color="k", label="2 Hz")    ax.plot(t, s1, lw=2, color="r", label="4 Hz")    ax.plot(t, s2, lw=2, color="g", label="6 Hz")    app = QtWidgets.QApplication(sys.argv)    window = CustomGraphicView(parent=None, figure=fig)    window.show()    sys.exit(app.exec_())    # Or i may    # app = QtWidgets.QApplication(sys.argv)    # window = CustomGraphicView(parent=None, figure=None)    # window.set_figure(fig)    # window.show()    # sys.exit(app.exec_())

Viewing all articles
Browse latest Browse all 12141

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>