0

I now want to use the Custom Button function of matplotlib, refer to this document: https://matplotlib.org/stable/gallery/widgets/buttons.html, it works quite well. But when I want to combine it with PyQt5, I first create a main window with a button in it. When the button is clicked, a plot will pop up, but the button in the plot loses its response. code show as below:

import sys

import matplotlib.pyplot as plt
import numpy as np
from matplotlib.widgets import Button
from PyQt5.QtCore import pyqtSlot
from PyQt5.QtWidgets import QApplication, QPushButton, QWidget


class Index:
    ind = 0

    def __init__(self, l, freqs):
        self.l = l
        self.freqs = freqs

    def next(self, event):
        self.ind += 1
        i = self.ind % len(self.freqs)
        ydata = np.sin(2 * np.pi * self.freqs[i] * t)
        self.l.set_ydata(ydata)
        plt.draw()

    def prev(self, event):
        self.ind -= 1
        i = self.ind % len(self.freqs)
        ydata = np.sin(2 * np.pi * self.freqs[i] * t)
        self.l.set_ydata(ydata)
        plt.draw()


class App(QWidget):

    def __init__(self):
        super().__init__()
        self.title = 'PyQt5 button - pythonspot.com'
        self.left = 10
        self.top = 10
        self.width = 320
        self.height = 200
        self.initUI()

    def initUI(self):
        self.setWindowTitle(self.title)
        self.setGeometry(self.left, self.top, self.width, self.height)

        button = QPushButton('PyQt5 button', self)
        button.setToolTip('This is an example button')
        button.move(100, 70)
        button.clicked.connect(self.on_click)

        self.show()

    @pyqtSlot()
    def on_click(self):
        freqs = np.arange(2, 20, 3)
        fig, ax = plt.subplots()
        fig.subplots_adjust(bottom=0.2)
        t = np.arange(0.0, 1.0, 0.001)
        s = np.sin(2 * np.pi * freqs[0] * t)
        l, = ax.plot(t, s, lw=2)

        callback = Index(l, freqs)
        axprev = fig.add_axes([0.7, 0.05, 0.1, 0.075])
        axnext = fig.add_axes([0.81, 0.05, 0.1, 0.075])
        bnext = Button(axnext, 'Next')
        bnext.on_clicked(callback.next)
        bprev = Button(axprev, 'Previous')
        bprev.on_clicked(callback.prev)

        plt.show()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = App()
    sys.exit(app.exec_())

I want to know why?

In this question: matplotlib event doesn't work when I use button clicked connect in pyqt5, I see that it seems to define a window myself , and then embed matplotlib, but I don't understand why Is there a document that says we must do this?

I tried Macos, linux, windows, it works under macos, but the button doesn't respond under linux and windows. I suspect it has something to do with QCoreApplication::exec: The event loop is already running, but I don't understand why the qt problem affects matplotlib. Is the signal of matplotlib registered to pyqt5?

1 Answer 1

2

Yes, Yes, You need not to a PlotEx, ref to Why aren't the matplotlib checkboxes working in pyQt5?

I understood that is because the button is local var, I need a more big scope.

the right code is :

import sys

import matplotlib.pyplot as plt
import numpy as np
from matplotlib.widgets import Button
from PyQt5.QtCore import pyqtSlot
from PyQt5.QtWidgets import QApplication, QPushButton, QWidget


class Index:
    ind = 0

    def __init__(self, l, freqs, t):
        self.l = l
        self.freqs = freqs
        self.t = t

    def next(self, event):
        self.ind += 1
        i = self.ind % len(self.freqs)
        ydata = np.sin(2 * np.pi * self.freqs[i] * self.t)
        self.l.set_ydata(ydata)
        plt.draw()

    def prev(self, event):
        self.ind -= 1
        i = self.ind % len(self.freqs)
        ydata = np.sin(2 * np.pi * self.freqs[i] * self.t)
        self.l.set_ydata(ydata)
        plt.draw()


class App(QWidget):

    def __init__(self):
        super().__init__()
        self.title = 'PyQt5 button - pythonspot.com'
        self.left = 10
        self.top = 10
        self.width = 320
        self.height = 200
        self.initUI()

    def initUI(self):
        self.setWindowTitle(self.title)
        self.setGeometry(self.left, self.top, self.width, self.height)

        button = QPushButton('PyQt5 button', self)
        button.setToolTip('This is an example button')
        button.move(100, 70)
        button.clicked.connect(self.on_click)

        self.show()

    @pyqtSlot()
    def on_click(self):
        freqs = np.arange(2, 20, 3)
        fig, ax = plt.subplots()
        fig.subplots_adjust(bottom=0.2)
        t = np.arange(0.0, 1.0, 0.001)
        s = np.sin(2 * np.pi * freqs[0] * t)
        l, = ax.plot(t, s, lw=2)

        callback = Index(l, freqs, t)
        axprev = fig.add_axes([0.7, 0.05, 0.1, 0.075])
        axnext = fig.add_axes([0.81, 0.05, 0.1, 0.075])
        bnext = Button(axnext, 'Next')
        bnext.on_clicked(callback.next)
        bprev = Button(axprev, 'Previous')
        bprev.on_clicked(callback.prev)

        plt.bnext = bnext
        plt.bprev = bprev

        plt.show()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = App()
    sys.exit(app.exec_())

The difference is add (and fix some bugs):

        plt.bnext = bnext
        plt.bprev = bprev
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.