当前位置 博文首页 > Pyqt+matplotlib 实现实时画图案例

    Pyqt+matplotlib 实现实时画图案例

    作者:苏格拉倒 时间:2021-07-16 17:43

    需求分析:

    项目中根据测得的数据在界面上实时绘制

    运行环境:

    Python 3.7 + Matplotlib 3.0.2 + PyQt 5

    matplot官网给的相应的例子:

    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轴的元素个数是逐渐增加的。

    通过阅读上述 _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循环,不断的更新数据概率出现绘图不刷新和操作不响应(最小化操作会高概率出现该问题)

    解决方法1:

    我使用的是PlotWidget,remove后再addwidget,然后再重新绘制

    解决方法2:

    不使用while循环,使用QTime定时器

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

    两种方法都可以解决这个问题,推荐方法2

    据说使用while循环,需要在更新数据之后调用pg.QtGui.QApplication.processEvents()才能确保正常,这个本人试了不行,可能是我这边的原因吧

    以上为个人经验,希望能给大家一个参考,也希望大家多多支持站长博客。如有错误或未考虑完全的地方,望不吝赐教。

    jsjbwy
    下一篇:没有了