如何重写matplotlib.animation.FuncAnimation的animate方法?自定义动画函数传递额外参数的调用问题求助
嘿,我来帮你搞定这两个Matplotlib动画的问题!
其实Matplotlib的FuncAnimation压根不需要你去重写它类内部的animate方法——它的设计初衷就是让你传入自己写的帧更新函数来实现动画逻辑,完全没必要动原类的方法。具体怎么做呢:
- 先写一个符合要求的函数:这个函数的第一个参数会自动接收
frames参数生成的每一个帧索引/值,然后你在函数里实现该帧的绘图操作(比如更新线条数据、移动图形元素等),最后可以返回需要重绘的元素(可选,用来优化动画性能)。 - 把这个函数直接传给
FuncAnimation的func参数就行。
当然,如果你真的有特殊需求要子类化FuncAnimation并重写它的内部animate方法(一般不推荐哈),可以参考下面的代码:
import matplotlib.animation as animation class CustomFuncAnimation(animation.FuncAnimation): def animate(self, i): # 在这里写你的自定义帧更新逻辑 # 也可以先调用父类的方法再做修改 result = super().animate(i) # 加一些你的专属操作 return result
不过绝大多数场景下,直接传自定义更新函数就足够用了,没必要搞子类化。
你的问题核心很明确:你把函数调用的结果传给了FuncAnimation,而不是函数本身。FuncAnimation的func参数需要的是一个可调用的函数对象,不是函数执行完返回的东西。
为啥之前的写法不行?
你之前写的:
animation_1 = animation.FuncAnimation( fig, animate_all(70, all_positions_list, vel_list), # 这里直接执行了函数,传的是返回值 interval=200, frames=70, cache_frame_data=False, )
这里animate_all(...)会立刻执行,返回something,然后把这个something传给func——但something不是可调用的函数啊,动画自然跑不起来。
最靠谱的解决方案:用FuncAnimation的fargs参数(官方推荐)
FuncAnimation专门提供了fargs参数,就是用来给你的动画函数传额外参数的。你的animate_all函数定义已经完美适配这种方式(第一个参数是帧索引,后面跟着*fargs),所以直接这么写就行:
animation_1 = animation.FuncAnimation( fig, animate_all, # 这里传函数本身,别加括号调用! fargs=(all_positions_list, vel_list), # 额外参数打包成元组传进去 interval=200, frames=70, cache_frame_data=False, )
这样FuncAnimation会自动把frames生成的每一个索引值作为第一个参数传给animate_all,然后把fargs里的参数依次传进去,相当于每次调用animate_all(index, all_positions_list, vel_list),完全符合你的函数定义,frames自动传索引的机制也不会失效。
其他可选方法
如果你不想用fargs,也可以用lambda表达式包装一下:
animation_1 = animation.FuncAnimation( fig, lambda index: animate_all(index, all_positions_list, vel_list), # lambda接收帧索引,再转递给你的函数 interval=200, frames=70, cache_frame_data=False, )
或者用functools.partial绑定参数(不过这里要注意参数顺序,容易搞混,所以还是推荐前面两种方法):
from functools import partial # 用lambda包装的方式更直观,partial这里需要注意参数顺序,避免搞反 animate_partial = lambda index: animate_all(index, all_positions_list, vel_list)
总的来说,用fargs是最简洁、最符合官方设计的方式,既能保留frames自动传索引的功能,又能顺利传入你的额外参数。
内容的提问来源于stack exchange,提问作者Ollowain

