簡體   English   中英

如何在 PyQt5 和 matplotlib 中同時處理和顯示數據

[英]How to process data and display it simultaneously in PyQt5 and matplotlib

我正在嘗試擴展此處介紹的示例,說明如何將matplotlib圖集成到 PyQt5 window 中並在應用程序運行時對其進行更新。

我對上面鏈接的代碼所做的更改是 plot 更新時的條件,即代替計時器,我向應用程序添加了一個按鈕,該按鈕鏈接到名為simulate的 function 並運行for -循環。 在循環內部,我們調用update_plot function,其他一切都保持不變。

def simulate(self, ydata):
    for k in trange(0, 500, 10):
        tmp = np.random.uniform(0, 1, size=(2, 1000))
        self.xdata = tmp[0]
        self.ydata = tmp[1]
        self.update_plot()

完整的代碼是

import sys
from PyQt5.QtWidgets import QVBoxLayout, QSizePolicy, QWidget, QPushButton, QHBoxLayout, QSpacerItem
from PyQt5 import QtWidgets

from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
import random

import numpy as np
from time import sleep

import sys
import matplotlib
matplotlib.use('Qt5Agg')

from matplotlib.figure import Figure


class MplCanvas(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)
        super(MplCanvas, self).__init__(fig)

class MainWindow(QtWidgets.QMainWindow):

    def __init__(self):
        super(MainWindow, self).__init__()

        widget =  QWidget(self)
        self.setCentralWidget(widget)
        vlay = QVBoxLayout(widget)
        hlay = QHBoxLayout()
        vlay.addLayout(hlay)


        pybutton = QPushButton('Fit!', self)
        pybutton.clicked.connect(self.simulate)
        hlay2 = QHBoxLayout()
        hlay2.addWidget(pybutton)
        hlay2.addItem(QSpacerItem(1000, 10, QSizePolicy.Expanding))
        vlay.addLayout(hlay2)

        self.canvas = MplCanvas(self, width=5, height=4, dpi=100)
        vlay.addWidget(self.canvas)
        
        self.n_data = 999
        self.xdata = list(range(self.n_data))
        self.ydata = [random.uniform(0, 1) for i in range(self.n_data)]

        # We need to store a reference to the plotted line
        # somewhere, so we can apply the new data to it.
        self._plot_ref = None
        self.update_plot()

        self.show()


    def simulate(self):
        for k in range(0, 5):
            print(k)
            tmp = np.random.uniform(0, 1, size=(2,self.n_data))
            self.xdata = tmp[0]
            self.ydata = tmp[1]
            self.update_plot()
            sleep(0.5)
            

    def update_plot(self):
        # Drop off the first y element, append a new one.
        #self.ydata = self.ydata[1:] + [random.randint(0, 10)]

        # Note: we no longer need to clear the axis.
        if self._plot_ref is None:
            plot_refs = self.canvas.axes.plot(self.xdata, self.ydata, 'r')
            self._plot_ref = plot_refs[0]
        else:
            self._plot_ref.set_ydata(self.ydata)

        # Trigger the canvas to update and redraw.
        self.canvas.draw()


if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    w = MainWindow()
    app.exec_()

現在發生的情況是,每當您單擊按鈕時self.simulate()被調用,因此for循環開始......正如您在 function 中看到的那樣,我每次都調用self.update_plot ,但顯示的 plot 只會得到循環結束后更新,即 function 完成...

有人可以解釋發生了什么嗎?

我認為 Qt 僅在主事件循環空閑時刷新顯示。 因此,當您運行simulate方法時,它無法刷新。 對此的快速解決方法是在update_plot()之后添加app.processEvents() ) 。

如果您有幾個需要經常更新的 GUI 項目,那么 processEvents 技巧將不會很好地工作,您將不得不開始查看線程。 特別是 QThreads,因為它們的設計目的是與 Qt 配合得很好。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM