PyQT5 实时更新图

PyQT5 live updating plots

我需要帮助为这些图表中的每一个添加实时绘图。我尝试了很多解决方案,但每一个都让我的 window 崩溃。有没有我遗漏的简单修复方法?

下面是没有任何更新方法的代码:

import sys
from PyQt5.QtWidgets import QDialog, QApplication, QPushButton, QVBoxLayout
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolbar
import matplotlib.pyplot as plt
import pandas as pd


class Window(QDialog):

    def __init__(self, parent=None):
        super(Window, self).__init__(parent)
        self.figure = plt.figure(tight_layout=True)
        self.canvas = FigureCanvas(self.figure)
        self.toolbar = NavigationToolbar(self.canvas, self)

        self.button5 = QPushButton('Lane 5')
        self.button4 = QPushButton('Lane 4')
        self.button3 = QPushButton('Lane 3')
        self.button2 = QPushButton('Lane 2')
        self.button1 = QPushButton('Lane 1')

        self.button1.clicked.connect(self.plot1)
        self.button2.clicked.connect(self.plot2)
        self.button3.clicked.connect(self.plot3)
        self.button4.clicked.connect(self.plot4)
        self.button5.clicked.connect(self.plot5)

        layout = QVBoxLayout()
        layout.addWidget(self.toolbar)
        layout.addWidget(self.canvas)
        layout.addWidget(self.button1)
        layout.addWidget(self.button2)
        layout.addWidget(self.button3)
        layout.addWidget(self.button4)
        layout.addWidget(self.button5)
        self.setLayout(layout)

    def plot1(self):
        data = pd.read_csv("2021-08-13.csv", parse_dates=['time'], infer_datetime_format=True)
        datafilter = data[data.lane == "Lane 1 Op2"]
        datafilter['time'] = pd.to_datetime(datafiltr['time'], errors='coerce')
        df = datafilter['time'].groupby(datafilter.godzina.dt.to_period("H")).agg('count')
        y = [df.index[i].to_timestamp() for i in range(len(df))]
        self.figure.clear()
        ax = self.figure.add_subplot(111)
        ax.bar(y, df, width=0.035)
        self.canvas.draw()

if __name__ == '__main__':
    app = QApplication(sys.argv)
    main = Window()
    main.show()
    sys.exit(app.exec_())

这里是 csv 文件示例:

lane,detail,time,potentiometer,piece,tooltime
Lane 3 Op3,3584,00:00:03,100%,873,0:00:58
Lane 3 Op2,00:00:20,150,,,
Lane 4 Op3,00:01:40,811,,,
Lane 3 Op1,1584,00:00:20,100%,149,0:01:32
Lane 2 Op2,2508,00:00:40,110%,151,0:01:49
Lane 3 Op1,00:00:34,149,,,
Lane 2 Op3,3508,00:00:56,100%,551,0:01:05
Lane 2 Op2,00:00:25,151,,,
Lane 3 Op3,00:01:07,873,,,
Lane 4 Op2,2858,00:01:31,100%,104,0:02:34
Lane 4 Op3,3858,00:01:32,100%,812,0:01:20
Lane 2 Op1,1508,00:01:33,100%,152,0:01:35
Lane 1 Op1,1141,00:01:38,100%,125,0:01:49
Lane 1 Op2,1141,00:01:38,100%,125,0:01:49
Lane 3 Op2,2584,00:01:51,100%,151,0:01:45

您的代码中存在一些问题。我建议您将此添加到您的代码中:

import traceback

def handle_exception(exc_type, exc_value, exc_traceback):
    print("".join(traceback.format_exception(exc_type, exc_value, exc_traceback)))
    sys.exit(1)

if __name__ == '__main__':
    sys.excepthook = handle_exception
    app = QApplication(sys.argv)
    main = Window()
    main.show()
    sys.exit(app.exec_())

这样,每个会导致您的 window 崩溃的错误都会被打印出来,这样您就可以看到发生了什么。


我得到的第一个错误是:

Traceback (most recent call last):
  File "C:/Users/main.py", line 60, in <module>
    main = Window()
  File "C:/Users/main.py", line 26, in __init__
    self.button2.clicked.connect(self.plot2)
AttributeError: 'Window' object has no attribute 'plot2'

__init__ 方法中,您将一些信号连接到未定义的函数 self.plot2self.plot3 等等。


如果我评论这些行,那么我得到:

Traceback (most recent call last):
  File "C:/Users/main.py", line 44, in plot1
    datafilter['time'] = pd.to_datetime(datafiltr['time'], errors='coerce')
NameError: name 'datafiltr' is not defined

这是 datafilter 中的错字。


修正了这个错字,我得到:

Traceback (most recent call last):
  File "C:/Users/main.py", line 45, in plot1
    df = datafilter['time'].groupby(datafilter.godzina.dt.to_period("H")).agg('count')
  File "C:\Users\VENV\stack\lib\site-packages\pandas\core\generic.py", line 5141, in __getattr__
    return object.__getattribute__(self, name)
AttributeError: 'DataFrame' object has no attribute 'godzina'

这是为了解决翻译问题,正如您已经指出的那样:godzina --> time.


最后,解决了所有这些问题,我开始工作了 window:

工作代码

import sys
from PyQt5.QtWidgets import QDialog, QApplication, QPushButton, QVBoxLayout
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolbar
import matplotlib.pyplot as plt
import pandas as pd

import traceback


class Window(QDialog):

    def __init__(self, parent=None):
        super(Window, self).__init__(parent)
        self.figure = plt.figure(tight_layout=True)
        self.canvas = FigureCanvas(self.figure)
        self.toolbar = NavigationToolbar(self.canvas, self)

        self.button5 = QPushButton('Lane 5')
        self.button4 = QPushButton('Lane 4')
        self.button3 = QPushButton('Lane 3')
        self.button2 = QPushButton('Lane 2')
        self.button1 = QPushButton('Lane 1')

        self.button1.clicked.connect(self.plot1)
        # self.button2.clicked.connect(self.plot2)
        # self.button3.clicked.connect(self.plot3)
        # self.button4.clicked.connect(self.plot4)
        # self.button5.clicked.connect(self.plot5)

        layout = QVBoxLayout()
        layout.addWidget(self.toolbar)
        layout.addWidget(self.canvas)
        layout.addWidget(self.button1)
        layout.addWidget(self.button2)
        layout.addWidget(self.button3)
        layout.addWidget(self.button4)
        layout.addWidget(self.button5)
        self.setLayout(layout)

    def plot1(self):
        data = pd.read_csv("2021-08-13.csv", parse_dates=['time'], infer_datetime_format=True)
        datafilter = data[data.lane == "Lane 1 Op2"]
        datafilter['time'] = pd.to_datetime(datafilter['time'], errors='coerce')
        df = datafilter['time'].groupby(datafilter.time.dt.to_period("H")).agg('count')
        y = [df.index[i].to_timestamp() for i in range(len(df))]
        self.figure.clear()
        ax = self.figure.add_subplot(111)
        ax.bar(y, df, width=0.035)
        self.canvas.draw()

def handle_exception(exc_type, exc_value, exc_traceback):
    print("".join(traceback.format_exception(exc_type, exc_value, exc_traceback)))
    sys.exit(1)


if __name__ == '__main__':
    sys.excepthook = handle_exception
    app = QApplication(sys.argv)
    main = Window()
    main.show()
    sys.exit(app.exec_())
    

但是我收到警告信息:

SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
  datafilter['time'] = pd.to_datetime(datafilter['time'], errors='coerce')