【问题标题】:How to interactively change the animation arguments如何以交互方式更改动画参数
【发布时间】:2022-10-23 17:51:19
【问题描述】:

早上好,

我想要达到的目标:

  • 我想根据 GUI 提供的值以交互方式更改 matplotlib.animation 参数。

例子:

  • 我准备了一个示例代码,如下所示,我试图根据用户通过使用 tkinter 创建的 spinBox 提供的值来更改动画的间隔参数。

问题:

  • 为了能够更新其参数,我想将我的动画调用到旋转框调用的回调函数中。但如果我这样做,我会收到以下错误消息“用户警告:动画被删除而没有渲染任何东西。这很可能是无意的。为防止删除,请将动画分配给只要您需要动画就存在的变量。”
  • 如果我将动画调用到主代码中,那么我将无法以交互方式更改其参数

问题:

  • 如何以交互方式更改动画参数,即基于用户可以在 tkinter 小部件中设置的值?

谢谢

示例代码:

import tkinter as tk
from random import randint
import matplotlib as plt
import matplotlib.animation as animation
import matplotlib.backends.backend_tkagg as tkagg


#Creating an instance of the Tk class
win = tk.Tk() 

#Creating an instance of the figure class
fig = plt.figure.Figure() 
#Create a Canvas containing fig into win
aCanvas =tkagg.FigureCanvasTkAgg(fig, master=win)
#Making the canvas a tkinter widget
aFigureWidget=aCanvas.get_tk_widget()
#Showing the figure into win as if it was a normal tkinter widget
aFigureWidget.grid(row=0, column=0)


#Defining the animation
ax = fig.add_subplot(xlim=(0, 1),  ylim=(0, 1))
(line,) = ax.plot([],[], '-')
CumulativeX, CumulativeY = [], []



# Providing the input data for the plot for each animation step
def update(i):
    CumulativeX.append(randint(0, 10) / 10)
    CumulativeY.append(randint(0, 10) / 10)
    return line.set_data(CumulativeX, CumulativeY)

spinBoxValue=1000
    
#When the button is pushed, get the value
def button():
    spinBoxValue=aSpinbox.get()

#Running the animation
ani=animation.FuncAnimation(fig, update, interval=spinBoxValue,  repeat=True)

#Creating an instance of the Spinbox class
aSpinbox = tk.Spinbox(master=win,from_=0, to=1000, command=button)
#Placing the button
aSpinbox .grid(row=2, column=0)


#run the GUI
win.mainloop()

【问题讨论】:

  • 您能否澄清您是否想在获得新输入时从头开始动画,或者按钮与动画是否有任何其他关系?
  • 在我的完整代码中,我使用 tkinter 来提供一些输入。单击 tkinter 按钮后,我想 a) 完全清除上一个动画,b) 我想使用一些输入来计算将修改 line.set_data 的新列表(CumulativeX 和 CumulativeY 中的值,如果你愿意) 和 c) 剩余的输入必须改变 animate 函数本身的参数。

标签: python matplotlib tkinter animation callback


【解决方案1】:

当在函数button 中创建动画时,我们必须使用fig.canvas.draw() 重绘动画:

def button():
    global spinBoxValue, CumulativeX, CumulativeY, ani
    spinBoxValue = aSpinbox.get()
    CumulativeX, CumulativeY = [], [] # This is optional
    
    # To stop the background animation
    ani.event_source.stop()
    
    # Unlink/delete the reference to the previous animation 
    # del ani

    ani=animation.FuncAnimation(fig, update, interval=int(spinBoxValue) * 1000,  repeat=False)
    fig.canvas.draw()

在提供的代码中,当它使用来自aSpinbox.get() 的值重新创建动画时,它绘制线条太快了,所以我将输入更改为整数以使用interval=int(spinBoxvalue) * 1000button 函数中以较慢的速度绘制动画.

关于删除动画

由于我们必须停止背景动画并在按下按钮时运行新生成的动画,并且因为an animation must be stored in a variable as long as it runs,我们将不得不通过相同的变量名来引用上一个和最新的动画。

我们可以删除存储在全局变量ani中的动画,在ani.event_source.stop()之后使用del ani,这样会丢失对按下按钮之前存储在内存中的动画的引用,but we can't really free the memory address这里的引用被ani已制作(我猜只要我们在 Python 中使用默认的垃圾收集方法,这就是真的)。


编辑

跳转到新动画不会更新/删除此处在轴上创建的任何变量 - 我们必须明确处理它。要在按下按钮后只更新一次变量,首先在代码的全局范围内创建这些变量,然后在 button 函数中删除它们,并在使用 fig.canvas.draw 之前/之后重新创建/定义它们:

# Defined in global scope
text = ax.text(0.7, 0.5, "text")

def button():
    global spinBoxValue, CumulativeX, CumulativeY, ani, text
    spinBoxValue = int(aSpinbox.get())

    # To stop the background animation
    ani.event_source.stop()

    CumulativeX, CumulativeY = [], []   
    
    # Unlink/delete the reference to the previous animation 
    # del ani

    text.remove()
    text = ax.text(0.7 * spinBoxValue/10 , 0.5, "text")

    ani=animation.FuncAnimation(fig, update, interval=spinBoxValue*1000, repeat=False)
    fig.canvas.draw()

【讨论】:

  • 谢谢。单击旋转框后,如何完全刷新动画?我提供的代码是一个简化的案例,我可以在其中清除 2 个列表(CumulativeX 和 CumulativeY)。但是,在我的完整代码中,我不能简单地这样做。 (当我尝试时,第一个动画与新动画一起在后台继续运行)。在运行新动画之前如何销毁旧动画?谢谢
  • @Francesco您能否检查答案中更新的button 函数现在是否停止背景动画?我还在寻找删除旧动画,但最新答案可能只是解决问题。
  • 非常感谢你的帮助。不幸的是,您编辑的按钮不起作用。好吧,实际上对于简单的情况,我们正在努力,确实如此,但这只是因为我们正在清除 CumulativeX 和 Y 列表。所以,看起来它正在工作,但实际上我们并没有清除动画,而只是清除了动画所绘制的内容。例如,如果将 ax.text(0.7,0.5,'test') 添加到按钮函数中,那么您会看到每次按下按钮时都会将 'test' txt 叠加在一起,所以动画还没有真正重新启动。请问还有什么帮助吗?
  • 乐意效劳!你能检查一下最新的答案是否有帮助吗? :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-04-16
  • 2018-04-16
  • 2023-04-03
  • 2023-02-13
  • 2013-01-01
  • 1970-01-01
相关资源
最近更新 更多