Python 使用PyQt5和Matplotlib制作动态图形

Python 使用PyQt5和Matplotlib制作动态图形,python,animation,matplotlib,Python,Animation,Matplotlib,我想读取数据并绘制动态图,所以我学习了使用PyQt5的matplotlib。我找到了示例,但它是针对PyQt4的。我将其修改为PyQt5,但它有一些问题,当我单击开始按钮时,它显示错误 回溯(最近一次调用上次):文件 “/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site packages/matplotlib/backend_base.py”, 第1305行,在_on_timer ret=func(*args,

我想读取数据并绘制动态图,所以我学习了使用PyQt5的matplotlib。我找到了示例,但它是针对PyQt4的。我将其修改为PyQt5,但它有一些问题,当我单击开始按钮时,它显示错误

回溯(最近一次调用上次):文件 “/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site packages/matplotlib/backend_base.py”, 第1305行,在_on_timer ret=func(*args,**kwargs)文件中 “/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site packages/matplotlib/animation.py”, 第1049行,在_stepstill _go=Animation._step(self,*args)文件中 “/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site packages/matplotlib/animation.py”, 第855行,在步骤self.\u中绘制下一帧(framedata,self.\u blit)文件 “/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site packages/matplotlib/animation.py”, 第873行,在_draw_next_frame self._pre_draw(framedata,blit)文件中 “/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site packages/matplotlib/animation.py”, 第886行,在“绘制前的自绘制”中, self.\u blit\u缓存)文件 “/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site packages/matplotlib/animation.py”, 第926行,在a.figure.canvas.restore\u区域中(bg\u缓存[a]) KeyError:matplotlib.axes.\u subPlot.AxesSubplot对象位于0x1067718d0

这是我的密码,有人能帮我吗

import sys, os, random
from PyQt5 import QtCore
from PyQt5.QtWidgets import *

import numpy as np
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
import matplotlib.animation as animation

class MyMplCanvas(FigureCanvas):
    """Ultimately, this is a QWidget (as well as a FigureCanvasAgg, etc.)."""
    def __init__(self, parent=None, width=5, height=4, dpi=100):
        fig = Figure(figsize=(width, height), dpi=dpi)
        self.axes = fig.add_subplot(111)
        # We want the axes cleared every time plot() is called
        self.axes.hold(False)

        self.compute_initial_figure()

        #
        FigureCanvas.__init__(self, fig)
        self.setParent(parent)

    def compute_initial_figure(self):
        pass

class AnimationWidget(QWidget):
    def __init__(self):
        QMainWindow.__init__(self)

        vbox = QVBoxLayout()
        self.canvas = MyMplCanvas(self, width=5, height=4, dpi=100)
        vbox.addWidget(self.canvas)

        hbox = QHBoxLayout()
        self.start_button = QPushButton("start", self)
        self.stop_button = QPushButton("stop", self)
        self.start_button.clicked.connect(self.on_start)
        self.stop_button.clicked.connect(self.on_stop)
        hbox.addWidget(self.start_button)
        hbox.addWidget(self.stop_button)
        vbox.addLayout(hbox)
        self.setLayout(vbox)

        self.x = np.linspace(0, 5*np.pi, 400)
        self.p = 0.0
        self.y = np.sin(self.x + self.p)
        self.line, = self.canvas.axes.plot(self.x, self.y, animated=True, lw=2)




    def update_line(self, i):
        self.p += 0.1
        y = np.sin(self.x + self.p)
        self.line.set_ydata(y)
        return [self.line]

    def on_start(self):
        self.ani = animation.FuncAnimation(self.canvas.figure, self.update_line,
                                 blit=True, interval=25)

    def on_stop(self):
        self.ani._stop()



if __name__ == "__main__":
    qApp = QApplication(sys.argv)
    aw = AnimationWidget()
    aw.show()
    sys.exit(qApp.exec_())

我尝试了你的代码,似乎只有当你点击开始两次而不停止动画时才会出现真正的问题

解决这个问题的一种方法(不涉及动画情节的细节)是防止“开始”和“停止”按钮在它们不应该做的时候做任何事情

方法是向
AnimationWidget
类添加一个属性,该属性记录动画是否正在播放。所以把它放在
AnimationWidget
\uuuu init\uuuu
方法中的某个地方:

self.playing = False
然后,将启动时的
和停止时的
方法更改为

def on_start(self):
    if self.playing:
        pass
    else:
        self.playing = True
        self.ani = animation.FuncAnimation(
            self.canvas.figure,
            self.update_line,
            blit=True, interval=25
        )

这使得动画不会启动两次,并且不会出现错误和图形故障

def on_stop(self):
    if self.playing:
        self.playing = False
        self.ani._stop()
    else:
        pass