PyQt结合Matplotlib实现实时动态绘图与数据刷新优化方案

Theo
Theo
发布时间:2026-10-12 | 2人浏览过
原创

本文详解如何在PyQt5环境中使用Matplotlib实现基于实时数据的动态绘图。针对x、y轴数据动态增加的场景,通过修改_update_canvas函数实现数据累积绘制。此外,补充了pyqtgraph在高频更新中可能出现的界面卡顿问题,对比了移除重绘与QTimer定时器两种解决方案,推荐使用定时器法以保障程序响应性。

需求分析

在项目开发中,需要根据实时采集到的数据在图形界面上进行动态绘制展示。

运行环境

Python 3.7 + Matplotlib 3.0.2 + PyQt 5

Matplotlib官方示例参考

import sys
import time
import numpy as np
from matplotlib.backends.qt_compat import QtCore, QtWidgets, is_pyqt5
if is_pyqt5():
  from matplotlib.backends.backend_qt5agg import (
    FigureCanvas, NavigationToolbar2QT as NavigationToolbar)
else:
  from matplotlib.backends.backend_qt4agg import (
    FigureCanvas, NavigationToolbar2QT as NavigationToolbar)
from matplotlib.figure import Figure
class ApplicationWindow(QtWidgets.QMainWindow):
  def __init__(self):
    super().__init__()
    self._main = QtWidgets.QWidget()
    self.setCentralWidget(self._main)
    layout = QtWidgets.QVBoxLayout(self._main)
    static_canvas = FigureCanvas(Figure(figsize=(5, 3)))
    layout.addWidget(static_canvas)
    self.addToolBar(NavigationToolbar(static_canvas, self))
    dynamic_canvas = FigureCanvas(Figure(figsize=(5, 3)))
    layout.addWidget(dynamic_canvas)
    self.addToolBar(QtCore.Qt.BottomToolBarArea,
            NavigationToolbar(dynamic_canvas, self))
    self._static_ax = static_canvas.figure.subplots()
    t = np.linspace(0, 10, 501)
    self._static_ax.plot(t, np.tan(t), ".")
    self._dynamic_ax = dynamic_canvas.figure.subplots()
    self._timer = dynamic_canvas.new_timer(
      100, [(self._update_canvas, (), {})])
    self._timer.start()
  def _update_canvas(self):
    self._dynamic_ax.clear()
    t = np.linspace(0, 10, 101)
    # Shift the sinusoid as a function of time.
    self._dynamic_ax.plot(t, np.sin(t + time.time()))
    self._dynamic_ax.figure.canvas.draw()
if __name__ == "__main__":
  qapp = QtWidgets.QApplication(sys.argv)
  app = ApplicationWindow()
  app.show()
  qapp.exec_()

官方示例中,上方图表显示为静止散点,下方图表则呈现类似行波的动态效果,这是因为使用了**self._dynamic_ax.plot(t, np.sin(t + time.time()))**函数。然而,该示例并非典型的实时数据绘图场景,其x轴和y轴的数据点数量是固定的。在实际项目中,我们需要根据生成的数据实时绘图,这意味着x轴和y轴的元素个数会随着时间逐渐增加。

通过阅读上述_update_canvas函数代码以及dynamic_canvas.new_timer机制,可以实现每次调用_update_canvas时,x轴和y轴的元素数量逐步增加。修改后的代码如下:

import sys
import time
import numpy as np
from matplotlib.backends.qt_compat import QtCore, QtWidgets, is_pyqt5
if is_pyqt5():
  from matplotlib.backends.backend_qt5agg import (
    FigureCanvas, NavigationToolbar2QT as NavigationToolbar)
else:
  from matplotlib.backends.backend_qt4agg import (
    FigureCanvas, NavigationToolbar2QT as NavigationToolbar)
from matplotlib.figure import Figure
class ApplicationWindow(QtWidgets.QMainWindow):
  def __init__(self):
    super().__init__()
    self._main = QtWidgets.QWidget()
    self.setCentralWidget(self._main)
    layout = QtWidgets.QVBoxLayout(self._main)
    static_canvas = FigureCanvas(Figure(figsize=(5, 3)))
    layout.addWidget(static_canvas)
    self.addToolBar(NavigationToolbar(static_canvas, self))
    dynamic_canvas = FigureCanvas(Figure(figsize=(5, 3)))
    layout.addWidget(dynamic_canvas)
    self.addToolBar(QtCore.Qt.BottomToolBarArea,
            NavigationToolbar(dynamic_canvas, self))
    self._static_ax = static_canvas.figure.subplots()
    t = np.linspace(0, 10, 501)
    self._static_ax.plot(t, np.tan(t), ".")
    self.x = [] #建立空的x轴数组和y轴数组
    self.y = []
    self.n = 0
    self._dynamic_ax = dynamic_canvas.figure.subplots()
    self._timer = dynamic_canvas.new_timer(
      100, [(self._update_canvas, (), {})])
    self._timer.start()
    
  def _update_canvas(self):
    self.n += 1
    if self.n == 200:      #画200个点就停止,根据实际情况确定终止条件
      self._timer.stop()   
    self._dynamic_ax.clear()
    self.x.append(np.pi/100*self.n) #x加入一个值,后一个值比前一个大pi/100
    xx = np.array(self.x)
    # t = np.linspace(0, 10, 101)
    # Shift the sinusoid as a function of time.
    self._dynamic_ax.plot(xx, np.sin(xx))
    self._dynamic_ax.set_xlim(0,7)
    self._dynamic_ax.set_ylim(-1,1)
    self._dynamic_ax.figure.canvas.draw()
if __name__ == "__main__":
  qapp = QtWidgets.QApplication(sys.argv)
  app = ApplicationWindow()
  app.show()
  qapp.exec_()

修改后,上图依然保持静止,而下图可以实时显示动态变化。

补充说明:pyqtgraph实时绘图时可能遇到的刷新问题

在使用pyqtgraph进行实时绘图时,偶尔会出现图表无法及时刷新的情况。

while True:
  ......
  update()  # 通过 plotitem.setData()更新数据
  ......

这通常是因为使用了while循环来不断更新数据,导致绘图刷新和操作响应(如窗口最小化)概率性失效。

解决方法一

若使用的是PlotWidget,可以通过先remove再addwidget的方式,然后重新绘制图表来解决。

解决方法二

避免使用while循环,改用QTime定时器来触发数据更新。

t = QTimer()
t.timeout.connect(self.update)
t.start(10)

上述两种方法均可解决问题,但推荐使用方法二。

有观点认为,若必须使用while循环,需在更新数据后调用pg.QtGui.QApplication.processEvents()以确保正常显示。但经本人测试,该方法在本环境中无效,可能是环境差异所致。

以上为个人经验分享,希望能为大家提供参考。欢迎大家支持本站。如有错误或考虑不周之处,敬请指正。

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表