Matplotlib is hiring a Research Software Engineering Fellow! See discourse for details. Apply by January 3, 2020
在Matplotlib中制作动态动画最简单的方法是使用 Animation
类。
FuncAnimation |
通过重复调用函数制作动画 func . |
ArtistAnimation |
使用一组固定的动画 Artist 物体。 |
在这两种情况下,保持对实例对象的引用至关重要。动画是由计时器(通常来自主机GUI框架)进行的,该计时器 Animation
对象保存对的唯一引用。如果您不持有对 Animation
对象(以及计时器)将被垃圾收集,从而停止动画。
要将动画保存到磁盘,请使用 Animation.save
或 Animation.to_html5_video
见 辅助类 下面是关于支持哪些电影格式的详细信息。
FuncAnimation
¶内部工作 FuncAnimation
或多或少是:
for d in frames:
artists = func(d, *fargs)
fig.canvas.draw_idle()
fig.canvas.start_event_loop(interval)
通过细节处理“Blitting”(显著提高实时性能)、不阻塞、不重复启动/停止GUI事件循环、处理重复、多个动画轴,并轻松将动画保存到电影文件中。
“BLIT”是一个 old technique 在计算机图形学中。一般的要点是采取一个现有的位图(在我们的情况下,主要是栅格化的数字),然后'闪电'一个以上的艺术家。因此,通过管理保存的“干净”位图,我们只能重新绘制在每帧上都发生变化的少数艺术家,并可能节省大量时间。当我们使用Blitting(路过 blit=True
)的核心循环 FuncAnimation
变得更加复杂:
ax = fig.gca()
def update_blit(artists):
fig.canvas.restore_region(bg_cache)
for a in artists:
a.axes.draw_artist(a)
ax.figure.canvas.blit(ax.bbox)
artists = init_func()
for a in artists:
a.set_animated(True)
fig.canvas.draw()
bg_cache = fig.canvas.copy_from_bbox(ax.bbox)
for f in frames:
artists = func(f, *fargs)
update_blit(artists)
fig.canvas.start_event_loop(interval)
当然,这会遗漏许多细节(例如,在调整图形大小或完全重新绘制图形时更新背景)。然而,这个可能是极简主义的例子给出了一个如何 init_func
和 func
在…内部使用 FuncAnimation
以及“闪电”如何工作的理论。
上的预期签名 func
和 init_func
很容易保存 FuncAnimation
从你的簿记和绘图逻辑,但这意味着,你传递的可调用对象必须知道他们应该工作的艺术家。有几种方法可以处理这一问题,它们具有不同的复杂性和封装性。对于脚本来说,最简单的方法是在全局范围内定义艺术家,并让Python进行排序,这在脚本的情况下非常有效。例如::
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
fig, ax = plt.subplots()
xdata, ydata = [], []
ln, = plt.plot([], [], 'ro')
def init():
ax.set_xlim(0, 2*np.pi)
ax.set_ylim(-1, 1)
return ln,
def update(frame):
xdata.append(frame)
ydata.append(np.sin(frame))
ln.set_data(xdata, ydata)
return ln,
ani = FuncAnimation(fig, update, frames=np.linspace(0, 2*np.pi, 128),
init_func=init, blit=True)
plt.show()
第二种方法是 functools.partial
将艺术家“绑定”到功能。第三种方法是使用闭包来构建所需的艺术家和函数。第四种方法是创建类。
ArtistAnimation
¶提供的作家可分为几个大类。
枕头作者依靠枕头库来编写动画,将所有数据保存在内存中。
PillowWriter |
基于管道的编写器通过管道将捕获的帧流式传输到外部进程。基于管道的变体往往更具性能,但可能不适用于所有系统。
FFMpegWriter |
基于管道的ffmpeg编写器。 |
ImageMagickWriter |
基于管道的动画GIF。 |
AVConvWriter |
基于管道的AVconv编写器。 |
基于文件的编写器为每个帧保存临时文件,这些帧在结尾处缝合成单个文件。虽然速度较慢,但这些编写器更容易调试。
FFMpegFileWriter |
基于文件的ffmpeg编写器。 |
ImageMagickFileWriter |
基于文件的动画gif书写器。 |
AVConvFileWriter |
基于文件的avconv编写器。 |
基本上,A MovieWriter
提供从同一底层获取连续帧的方法 Figure
对象。基类 MovieWriter
实现3个方法和一个上下文管理器。基于管道和基于文件的编写器之间的唯一区别在于它们各自的参数 setup
方法。
这个 setup()
方法用于准备编写器(可能打开管道)、对 grab_frame()
一次捕获一帧,然后 finish()
完成电影并将输出文件写入磁盘。例如::
moviewriter = MovieWriter(...)
moviewriter.setup(fig=fig, 'my_movie.ext', dpi=100)
for j in range(n):
update_figure(n)
moviewriter.grab_frame()
moviewriter.finish()
如果直接使用writer类(而不是通过 Animation.save
)强烈建议使用 saving
上下文管理器:
with moviewriter.saving(fig, 'myfile.mp4', dpi=100):
for j in range(n):
update_figure(n)
moviewriter.grab_frame()
以确保根据需要执行设置和清理。
Animation |
此类使用matplotlib包装动画的创建。 |
TimedAnimation |
Animation 基于时间的动画的子类。 |
提供了一个模块级注册表,用于在编写器的名称和类之间进行映射,以允许将字符串传递给 Animation.save
而不是编写器实例。
MovieWriterRegistry |
按人类可读的名称注册可用的编写器类。 |
减少代码重复的基类
AbstractMovieWriter |
用于编写电影的抽象基类。 |
MovieWriter |
用于编写电影的基类。 |
FileMovieWriter |
MovieWriter 用于写入单个文件并在末尾缝合。 |
和混音
AVConvBase |
用于avconv输出的mixin类。 |
FFMpegBase |
用于ffmpeg输出的mixin类。 |
ImageMagickBase |
ImageMagick输出的Mixin类。 |
提供。
有关如何轻松实现新的 MovieWriter
类。