【问题标题】:Calling FuncAnimation() when it is inside a function在函数内部调用 FuncAnimation()
【发布时间】:2020-08-19 07:53:37
【问题描述】:

我正在尝试在调用特定函数时执行 FuncAnimation()。但是,我的情节没有得到任何结果。

当 FuncAnimation 不在函数内部(或在 __init__() 内部)时,它可以完美运行。

我尝试了所有已发布的与该问题相关的解决方案,但它们在我的代码中不起作用。

我的简化代码是:

import sys
import os
from datetime import datetime
import matplotlib
from PyQt5 import QtCore, QtWidgets
from PyQt5.QtWidgets import QApplication, QMainWindow, QVBoxLayout, QSizePolicy, QWidget
import numpy as np
import random
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
from matplotlib.animation import FuncAnimation

class MyMplCanvas(FigureCanvas):
    def __init__(self, parent=None, width=5, height=4, dpi=100):
        fig = Figure(figsize=(width, height), dpi=dpi)

        self.ax = fig.add_subplot(1,1,1)

        FigureCanvas.__init__(self, fig)
        self.setParent(parent)
        FigureCanvas.setSizePolicy(self,
                                   QtWidgets.QSizePolicy.Expanding,
                                   QtWidgets.QSizePolicy.Expanding)
        FigureCanvas.updateGeometry(self)

class ApplicationWindow(QtWidgets.QMainWindow):
    def __init__(self):
        QtWidgets.QMainWindow.__init__(self)
        self.main_widget = QtWidgets.QWidget(self)
        self.canvas =  MyMplCanvas( self.main_widget,width=6, height=6, dpi=100) 

        self.xdata = []
        self.ydata = []

        vbox = QtWidgets.QVBoxLayout(self.main_widget)

        self.start_button = QtWidgets.QPushButton(text="START")
        self.outer_ani = self.start_button.clicked.connect(self.start_func_animation)

        vbox.addWidget(self.canvas)
        vbox.addWidget(self.start_button)
        self.setLayout(vbox)
        self.main_widget.setFocus()
        self.setCentralWidget(self.main_widget)

    def start_func_animation(self):
        self.line, = self.canvas.ax.plot_date(self.xdata, self.ydata, linestyle='-', linewidth=0.6, markersize=2.5)
        self.ani = FuncAnimation(self.canvas.figure, self.update_line, interval=1000)

        return self.ani

    def update_line(self, i):
        self.xdata.append(datetime.now())
        self.ydata.append(1+np.random.randint(-3,3))

        self.line.set_data(self.xdata, self.ydata)
        self.canvas.figure.gca().relim()
        self.canvas.figure.gca().autoscale_view()
        self.canvas.ax.tick_params(axis='x', rotation=50)

        return self.line,


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

【问题讨论】:

  • update_lineFuncAnimation 调用的函数中没有调用 plot?
  • 对不起,我不太明白你的意思。请您详细解释一下好吗?
  • 我错了。 set_data 应该画。

标签: python matplotlib animation pyqt pyqt5


【解决方案1】:

解决方案是为它更新绘画,有两种选择:使用self.canvas.draw() 或在FuncAnimation 中设置blit=True

from datetime import datetime
import random
import os
import sys

from PyQt5 import QtCore, QtWidgets

import numpy as np

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


class MyMplCanvas(FigureCanvas):
    def __init__(self, parent=None, width=5, height=4, dpi=100):
        fig = Figure(figsize=(width, height), dpi=dpi)

        self.ax = fig.add_subplot(1, 1, 1)

        FigureCanvas.__init__(self, fig)
        self.setParent(parent)
        FigureCanvas.setSizePolicy(
            self, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding
        )
        FigureCanvas.updateGeometry(self)


class ApplicationWindow(QtWidgets.QMainWindow):
    def __init__(self):
        QtWidgets.QMainWindow.__init__(self)
        self.main_widget = QtWidgets.QWidget(self)
        self.canvas = MyMplCanvas(self.main_widget, width=6, height=6, dpi=100)

        self.xdata = []
        self.ydata = []

        vbox = QtWidgets.QVBoxLayout(self.main_widget)

        self.start_button = QtWidgets.QPushButton(text="START")
        # self.outer_ani = self.start_button.clicked.connect(self.start_func_animation)
        self.start_button.clicked.connect(self.start_func_animation)

        vbox.addWidget(self.canvas)
        vbox.addWidget(self.start_button)
        # self.setLayout(vbox)
        self.main_widget.setFocus()
        self.setCentralWidget(self.main_widget)

    def start_func_animation(self):
        (self.line,) = self.canvas.ax.plot_date(
            self.xdata, self.ydata, linestyle="-", linewidth=0.6, markersize=2.5
        )
        self.canvas.draw()
        self.ani = FuncAnimation(self.canvas.figure, self.update_line, interval=1000)
        # or
        # self.ani = FuncAnimation(self.canvas.figure, self.update_line, interval=1000, blit=True)
        # return self.ani

    def update_line(self, i):
        self.xdata.append(datetime.now())
        self.ydata.append(1 + np.random.randint(-3, 3))

        self.line.set_data(self.xdata, self.ydata)
        self.canvas.figure.gca().relim()
        self.canvas.figure.gca().autoscale_view()
        self.canvas.ax.tick_params(axis="x", rotation=50)

        return (self.line,)


if __name__ == "__main__":
    App = QtWidgets.QApplication(sys.argv)
    aw = ApplicationWindow()
    aw.show()
    # App.exit()
    sys.exit(App.exec_())

【讨论】:

  • 好的,非常感谢您的帮助!我看到它现在可以工作了。但是,对于使用 self.canvas.draw() 的解决方案,FuncAnimation 不应该足以制作没有这条线的动画情节吗?对于第二个选项(使用 blit),当我在 mac 上运行它时,它会在右下角显示为切口(这是一个 gif:gyazo.com/27d2fe7484251c9045f7496d5c3b1034),但是当我使用 Windows 时,它可以完美运行。你知道这可能是什么原因吗?
  • 1) 将艺术家作为“self.line”添加到画布时并不意味着它是自动绘制的(我怀疑 matplotlib 这样做是为了提高效率)所以你应该使用 draw 函数。 2)我不知道为什么在 Mac OS 中会发生这种行为,在 Linux 中它可以正常工作 blit = True。
  • 好的!最后,我注意到将 {self.canvas.draw()} 放在 FuncAnimation() 之后会返回更好的结果,因为在 FuncAnimation() 之前使用它时,会绘制一些意想不到的点。你也一样?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-01-12
  • 2017-12-06
  • 1970-01-01
  • 1970-01-01
  • 2016-11-15
  • 1970-01-01
  • 2021-02-10
相关资源
最近更新 更多