You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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)

二、主脚本中同步数据更新到绘图窗口

  1. 保留绘图窗口实例引用:在主脚本打开绘图窗口时,保存实例以便后续调用更新方法
# 主脚本中打开绘图窗口的示例代码
from plotter_module import PlotterWindow

# 假设已获取初始DataFrame
plotter_window = PlotterWindow(initial_df)
plotter_window.show()
  1. 改造表格更新函数,同步触发绘图更新:
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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 10:57:56