PyQT5 实时更新图
Posted
技术标签:
【中文标题】PyQT5 实时更新图【英文标题】:PyQT5 live updating plots 【发布时间】:2021-08-16 09:00:33 【问题描述】:我需要帮助来为每个图表添加实时绘图。我尝试了很多解决方案,但每一个都不断地让我的窗户崩溃。我缺少一个简单的修复方法吗?
下面是没有任何更新方法的代码:
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
【问题讨论】:
请问,您能否提供一个保存在2021-08-13.csv
中的数据样本?
Lane 5 Op2,2995,00:47:35,100%,18,1:19:29 我现在只使用时间(本例中为 00:47:35)
我的数据有问题,因为在您的代码中有对datafilter.godzina
的引用,而您提供的数据中没有。 godzina
是什么?
哦,对不起。 csv 文件是用波兰语制作的,所以我之前不得不使用一些波兰语名称。 godzina 的意思是小时,把它改成时间就行了。
@Jukel 错误信息是什么?打开 CMD/控制台并执行python /path/of/script.py
【参考方案1】:
您的代码中存在一些问题。我建议您将其添加到您的代码中:
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_())
这样,每一个会导致你的窗口崩溃的错误都会被打印出来,这样你就可以看到发生了什么。
我得到的第一个错误是:
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.plot2
、self.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
。
最后,解决了所有这些问题,我得到了工作窗口:
工作代码
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')
【讨论】:
非常感谢,有了回溯功能,一切都会变得容易得多。我希望我现在可以自己解决这个问题。祝你有美好的一天:) 请注意,虽然 Qt 有时会抛出“静默”错误,并且 IDE 通常不提供完整的反馈,但大多数问题都可以通过在终端/提示符中运行代码来跟踪,而不需要异常处理程序.以上是关于PyQT5 实时更新图的主要内容,如果未能解决你的问题,请参考以下文章