简体   繁体   English

输入用户数据时如何通过Matplotlib更新图(通过PyQt5按钮)

[英]How to update plot in Matplotlib when user data is inputted (via PyQt5 button)

I've been working on this code tirelessly throughout the day, but can't seem to figure out where my logic is off. 我整天一直在不懈地编写此代码,但似乎无法弄清楚我的逻辑在哪里。 I want the user to be able to browse for a file (here they are simply pressing a button called 'Browse') that immediately updates the shown plot (here going from blue lines to red in the plot; but ultimately in my actual program going from a blank plot to a filled one, or from a filled to a different filled one). 我希望用户能够浏览一个文件(在这里他们只是按一个名为“浏览”的按钮),该文件可以立即更新显示的图(这里从蓝线到红色);但最终在我的实际程序中从空白图到填充图,或从填充图到另一填充图)。

It's inspired by an example from https://matplotlib.org/examples/user_interfaces/embedding_in_qt5.html , but I've altered it quite a bit to express my current problem in a way that is most hopefully minimal and complete. 它的灵感来自https://matplotlib.org/examples/user_interfaces/embedding_in_qt5.html的示例,但是我已经对其进行了相当多的更改,以最有希望的最小和完整的方式表达我的当前问题。 Thank you so much in advance for even taking a look. 非常感谢您甚至来看看。

import sys
import os
import random
import matplotlib
matplotlib.use('Qt5Agg')
from PyQt5 import QtCore, QtWidgets
from PyQt5.QtWidgets import QGridLayout, QFileDialog, QPushButton

from numpy import arange
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure


class MyMplCanvas(FigureCanvas):

    def __init__(self, parent=None, width=5, height=4, dpi=100):
        fig = Figure(figsize=(width, height), dpi=dpi)
        self.axes = fig.add_subplot(111)

        self.compute_initial_figure()

        FigureCanvas.__init__(self, fig)
        self.setParent(parent)

        FigureCanvas.setSizePolicy(self,
                                   QtWidgets.QSizePolicy.Expanding,
                                   QtWidgets.QSizePolicy.Expanding)
        FigureCanvas.updateGeometry(self)

    def compute_initial_figure(self):
        pass


class MyDynamicMplCanvas(MyMplCanvas):
    """A canvas that updates itself every second with a new plot."""

    def __init__(self, *args, **kwargs):
        MyMplCanvas.__init__(self, *args, **kwargs)
        #timer = QtCore.QTimer(self)
        #timer.timeout.connect(self.update_figure)
        #timer.start(1000)

    def compute_initial_figure(self):
        self.axes.plot([0, 1, 2, 3], [1, 2, 0, 4], 'b')

    def update_figure(self):
        print('update')
        # Build a list of 4 random integers between 0 and 10 (both inclusive)
        l = [random.randint(0, 10) for i in range(4)]
        self.axes.cla()
        if P1.df is True:
            self.axes.plot(P1.df, l, 'r') #should change to red, but doesn't
        else:
            self.axes.plot([0, 1, 2, 3], l, 'b')
        self.draw()

class P1(QtWidgets.QWidget):

    df = False #datafile is originally empty

    def __init__(self, parent=None):
        super(P1, self).__init__(parent)
        layout = QGridLayout(self)

        self.button_browse = QPushButton('Browse', self)
        self.button_browse.clicked.connect(self.browseFile)
        layout.addWidget(self.button_browse, 1, 1, 1, 1)
        self.button_browse.show()

        dc = MyDynamicMplCanvas(self, width=5, height=4, dpi=100)
        layout.addWidget(dc, 2, 1, 1, 1)

    def browseFile(self): #user presses browse to load new datafile
        print(P1.df)
        P1.df = [0, 1, 2, 3] 
        print(P1.df)
        #loading new datafile needs to update plot:
        MyDynamicMplCanvas().update_figure()



class MainWindow(QtWidgets.QMainWindow):    
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.setAttribute(QtCore.Qt.WA_DeleteOnClose)

        self.stack = QtWidgets.QStackedWidget(self)
        P1f = P1(self)
        self.stack.addWidget(P1f)
        self.setCentralWidget(self.stack)

if __name__ == '__main__':
    qApp = QtWidgets.QApplication(sys.argv)
    aw = MainWindow()
    aw.show()
    sys.exit(qApp.exec_())

You have 2 errors: 您有2个错误:

  • When using MyDynamicMplCanvas().update_figure() you are creating a new MyDynamicMplCanvas() object that is different from dc = MyDynamicMplCanvas(self, width = 5, height = 4, dpi = 100) , so being a local variable is eliminated a never shown. 使用MyDynamicMplCanvas().update_figure()您将创建一个新的MyDynamicMplCanvas()对象,该对象与dc = MyDynamicMplCanvas(self, width = 5, height = 4, dpi = 100) ,因此避免了永远不会使用局部变量所示。

  • The second is that the sentence P1.df is True will never be true since P1.df is False or is a list. 第二个是句子P1.df为True,因为P1.df为False或为列表,所以永远不会为真。

The solution is to make a member of the class and changes if P1.df is True: to if P1.df: 解决方案是使该类成为成员并if P1.df is True:更改if P1.df is True: if P1.df:

class MyDynamicMplCanvas(MyMplCanvas):
    ...

    def update_figure(self):
        print('update')
        # Build a list of 4 random integers between 0 and 10 (both inclusive)
        l = [random.randint(0, 10) for i in range(4)]
        self.axes.cla()
        if P1.df:
            self.axes.plot(P1.df, l, 'r') #should change to red, but doesn't
        else:
            self.axes.plot([0, 1, 2, 3], l, 'b')
        self.draw()

class P1(QtWidgets.QWidget):
    df = False

    def __init__(self, parent=None):
        ...

        self.dc = MyDynamicMplCanvas(self, width=5, height=4, dpi=100)
        layout.addWidget(self.dc, 2, 1, 1, 1)

    def browseFile(self): #user presses browse to load new datafile
        P1.df = [0, 1, 2, 3]
        #loading new datafile needs to update plot:
        self.dc.update_figure()

...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM