如何在Qt Designer构建的PyQtGraph窗口中绘制DataFrame数据并实时更新
问题描述
我有一个主程序,导入了两个模块:
- 一个模块负责通过BLE连接ESP并通过Notify接收数据,随后将数据保存到Excel文件中,核心代码如下:
async def handle_uuid2_notify(self, sender, data): ir_values = numpy.frombuffer(data, dtype=numpy.uint32) for ir_value in ir_values: if ir_value: ir_list.append(ir_value) if len(spo2_list) == 100 and len(ir_list) == 100: global df, first_run new_data_available = True if first_run: df = pd.DataFrame({'Red': spo2_list, 'IR': ir_list}) df.to_excel(filename, index=False) elif new_data_available: new_data = pd.DataFrame({'Red': spo2_list, 'IR': ir_list}) df = pd.concat([df, new_data], ignore_index=True) df.to_excel(filename, index=False) global first_run_file global Dateiname if first_run_file: print(filename) Dateiname = filename first_run_file = False spo2_list.clear() ir_list.clear()
该函数通过多线程运行,主脚本中点击按钮即可启动线程。
- 主脚本中导入生成的文件名,将数据显示在表格中(此功能已实现),核心代码如下:
def updatethetable(): print("starte update") from safe_to_excel import Dateiname Datei_pandas = pd.read_excel(Dateiname, engine='openpyxl') model = QStandardItemModel() model.setHorizontalHeaderLabels(Datei_pandas.columns) table_view = rohdaten_window_ui.RohdatenTableView table_view.setModel(model) # 添加数据行 for row in range(Datei_pandas.shape[0]): data_row = [QStandardItem(str(item)) for item in Datei_pandas.iloc[row]] model.appendRow(data_row) # 将TableView与UI中的Frame关联 table_view = rohdaten_window_ui.RohdatenTableView table_view.setModel(model)
现在需要实现绘图功能:首先绘制DataFrame或Excel文件中的最新100条数据,之后逐条显示这100条数据,待该数组的100条数据全部显示完成后,加载新的100条数据。
已创建绘图模块并导入pyqtgraph,用Qt Designer制作了.ui文件并提升部件,核心代码如下:
import pyqtgraph as pg from PyQt6.QtWidgets import QMainWindow import pandas as pd uiclass, baseclass = pg.Qt.loadUiType("plotter_window.ui") class PlotterWindow(QMainWindow, uiclass): def __init__(self, df): super().__init__() self.setupUi(self) self.plot(df) def plot(self, df): spo2_list = pd.Series(df['Red'][:100]).astype(float) self.graphWidget.plot(spo2_list.values) def open_plotter_window(df): window = PlotterWindow(df) return window
已在主脚本中调用该模块创建绘图窗口,但不知如何实现数据的绘制与更新,无论是直接使用pandas DataFrame还是表格的最新100条数据。
实现方案
一、重构绘图窗口类,支持逐帧更新与批量加载
修改PlotterWindow类,添加数据缓存、定时器控制逐帧显示,以及新数据加载逻辑:
import pyqtgraph as pg from PyQt6.QtWidgets import QMainWindow from PyQt6.QtCore import QTimer import pandas as pd uiclass, baseclass = pg.Qt.loadUiType("plotter_window.ui") class PlotterWindow(QMainWindow, uiclass): def __init__(self, initial_df): super().__init__() self.setupUi(self) # 初始化数据状态 self.current_batch = initial_df['Red'].iloc[-100:].astype(float).values # 取最新100条 self.current_index = 0 # 当前显示到第几条 self.full_df = initial_df # 保存完整DataFrame # 配置绘图基础设置 self.graphWidget.clear() self.plot_curve = self.graphWidget.plot([], []) # 创建空曲线对象 self.graphWidget.setLabel('left', 'Red Value') self.graphWidget.setLabel('bottom', 'Index') # 定时器控制逐帧显示,间隔可根据需求调整(示例为50ms) self.update_timer = QTimer() self.update_timer.timeout.connect(self.update_plot_frame) self.update_timer.start(50) def update_plot_frame(self): if self.current_index < len(self.current_batch): # 逐帧添加数据点更新曲线 x_data = list(range(self.current_index + 1)) y_data = self.current_batch[:self.current_index + 1] self.plot_curve.setData(x_data, y_data) self.current_index += 1 else: # 当前批次显示完成,暂停定时器 self.update_timer.stop() def load_new_batch(self, new_df): # 更新完整数据集,取最新100条作为新批次 self.full_df = new_df self.current_batch = new_df['Red'].iloc[-100:].astype(float).values self.current_index = 0 # 重启定时器开始逐帧显示新批次 self.update_timer.start(50)
二、主脚本中同步数据更新到绘图窗口
- 保留绘图窗口实例引用:在主脚本打开绘图窗口时,保存实例以便后续调用更新方法
# 主脚本中打开绘图窗口的示例代码 from plotter_module import PlotterWindow # 假设已获取初始DataFrame plotter_window = PlotterWindow(initial_df) plotter_window.show()
- 改造表格更新函数,同步触发绘图更新:
def updatethetable(): print("starte update") from safe_to_excel import Dateiname Datei_pandas = pd.read_excel(Dateiname, engine='openpyxl') # 原表格更新逻辑保留 model = QStandardItemModel() model.setHorizontalHeaderLabels(Datei_pandas.columns) table_view = rohdaten_window_ui.RohdatenTableView table_view.setModel(model) for row in range(Datei_pandas.shape[0]): data_row = [QStandardItem(str(item)) for item in Datei_pandas.iloc[row]] model.appendRow(data_row) table_view.setModel(model) # 同步更新绘图窗口:检查当前批次是否显示完成,完成则加载新数据 global plotter_window if plotter_window.current_index >= len(plotter_window.current_batch): plotter_window.load_new_batch(Datei_pandas)
三、可选:实现数据自动更新触发
如果希望BLE数据保存后自动触发表格和绘图更新,可以在数据保存模块添加信号通知:
# 在safe_to_excel模块中导入PyQt信号 from PyQt6.QtCore import pyqtSignal, QObject class DataNotifier(QObject): data_updated = pyqtSignal(str) # 传递文件名 data_notifier = DataNotifier() # 修改handle_uuid2_notify函数,保存完成后发送信号 async def handle_uuid2_notify(self, sender, data): # 原数据处理逻辑保留 if len(spo2_list) == 100 and len(ir_list) == 100: # 原保存逻辑保留 # 发送数据更新信号 data_notifier.data_updated.emit(filename) spo2_list.clear() ir_list.clear()
然后在主脚本中连接信号,自动调用更新函数:
from safe_to_excel import data_notifier data_notifier.data_updated.connect(lambda _: updatethetable())
内容的提问来源于stack exchange,提问作者tenebris in kux
相关产品推荐
相关产品推荐

