tkinter 中嵌入的 matplotlib 动画:从未调用过更新函数

matplotlib animation embedded in tkinter : update function never called

我一直在尝试将 matplotlib 动画嵌入到 tkinter 中。 这个应用程序的目标是用 rk4 方法模拟一些微分方程,并随着模拟的进行显示实时图形。

事实上,情节正确地嵌入到 tkinter 框架中。 但是,动画从未 运行,我注意到从未调用过更新函数。

我一直在到处寻找,但我什么也没找到。

感谢您的帮助。

这是 GUI class 的代码示例,显示了我在哪里执行动画

  # called when I click on a button "start simulation"
  def plot_neutrons_flow(self):

    # getting parameters from the graphical interface 
    if not self._started: 
      I0 = float(self._field_I0.get())
      X0 = float(self._field_X0.get())
      flow0 = float(self._field_flow0.get())
      time_interval = float(self._field_time_interval.get())
      stop = int(self._field_stop.get())

      FLOW_CI = [I0, X0, flow0] # [I(T_0), X(T_0), PHI[T_0]]

      self._simulation = NeutronsFlow(
        edo=neutrons_flow_edo, 
        t0=0,
        ci=FLOW_CI,
        time_interval=time_interval,
        stop=hour_to_seconds(stop)
      )

      # launch the animation
      self._neutrons_flow_plot.animate(self._simulation)
      self._started = True

这是 matplotlib 动画的代码:

import matplotlib
import tkinter as tk
import matplotlib.pyplot as plt
import matplotlib.animation as animation

from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg 
from matplotlib.figure import Figure
from matplotlib import style

matplotlib.use("TkAgg")
style.use('seaborn-whitegrid')

class PlotAnimation(FigureCanvasTkAgg):
  def __init__(self, tk_root):
    self._figure = Figure(dpi=100)
    # bind plot to tkinter frame
    super().__init__(self._figure, tk_root)

    x_label = "Temps (h)"
    y_label = "Flux / Abondance"

    self._axes = self._figure.add_subplot(111, xlabel=x_label, ylabel=y_label, yscale="log")
    self.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=1)


  def update(self, interval):
    # this is never called

    # get data from rk4 simulation
    time_set = self._simulation.get_time_set()
    y_set = self._simulation.get_y_set()


    self._axes.clear()
    self._axes.plot(time_set, y_set, visible=True, linewidth=1)
    self._axes.legend(fancybox=True)

    # redraw canvas
    self.draw_idle()

  def animate(self, simulation):
    # this is called

    self._simulation = simulation
    # simulate differential equations with rk4 method
    self._simulation.resolve()

    # https://github.com/matplotlib/matplotlib/issues/1656
    anim = animation.FuncAnimation(
      self._figure, 
      self.update,
      interval=1000
    )

编辑:

解决方法是在init方法中直接实例化FuncAnimation函数

animation module(强调我的)

的文档中所示

(...) it is critical to keep a reference to the instance object. The animation is advanced by a timer (typically from the host GUI framework) which the Animation object holds the only reference to. If you do not hold a reference to the Animation object, it (and hence the timers), will be garbage collected which will stop the animation.

您需要 return 来自 animate() 函数的 anim 对象,并将其存储在代码中的某处,这样它就不会被垃圾回收