matplotlib.animation#

动画#

在 Matplotlib 中制作实时动画的最简单方法是使用其中一个 Animation 类。

参见

  • 动画

Inheritance diagram of matplotlib.animation.FuncAnimation, matplotlib.animation.ArtistAnimation

Animation

动画的基类。

FuncAnimation

TimedAnimation 子类,通过重复调用一个函数 func 来制作动画。

ArtistAnimation

TimedAnimation 子类,通过使用一组固定的 Artist 对象来创建动画。

在这两种情况下,保持对实例对象的引用至关重要。动画由计时器(通常来自主机GUI框架)推进,而 Animation 对象持有对该计时器的唯一引用。如果你不持有对 Animation 对象的引用,它(以及计时器)将被垃圾回收,从而停止动画。

要保存动画,请使用 Animation.saveAnimation.to_html5_videoAnimation.to_jshtml

有关支持的电影格式的详细信息,请参见下面的 辅助类

FuncAnimation#

FuncAnimation 的内部工作原理大致如下:

for d in frames:
    artists = func(d, *fargs)
    fig.canvas.draw_idle()
    fig.canvas.start_event_loop(interval)

详细处理 'blitting'(以显著提高实时性能),实现非阻塞,不重复启动/停止 GUI 事件循环,处理重复,多个动画轴,并轻松将动画保存到电影文件。

'Blitting' 是计算机图形学中的 标准技术 。其基本思路是取一个现有的位图(在我们的例子中是一个大部分栅格化的图形),然后在上面再 'blit' 一个艺术家。因此,通过管理一个保存的 '干净' 位图,我们只需重新绘制每一帧中正在变化的少数艺术家,从而可能节省大量时间。当我们使用 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_funcfunc 如何在 FuncAnimation 内部使用以及'blitting'工作原理的理论的感觉。

备注

在进行'blitting'时,不会考虑艺术家的zorder,因为'blitted'艺术家总是绘制在最上层。

funcinit_func 上的预期签名非常简单,以使 FuncAnimation 远离您的簿记和绘图逻辑,但这意味着您传递的可调用对象必须知道它们应该处理哪些艺术家。有几种方法可以处理这个问题,复杂性和封装性各不相同。最简单的方法,在脚本的情况下效果非常好,是在全局范围内定义艺术家,并让 Python 处理其余的事情。例如:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation

fig, ax = plt.subplots()
xdata, ydata = [], []
ln, = ax.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 将参数传递给函数:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
from functools import partial

fig, ax = plt.subplots()
line1, = ax.plot([], [], 'ro')

def init():
    ax.set_xlim(0, 2*np.pi)
    ax.set_ylim(-1, 1)
    return line1,

def update(frame, ln, x, y):
    x.append(frame)
    y.append(np.sin(frame))
    ln.set_data(x, y)
    return ln,

ani = FuncAnimation(
    fig, partial(update, ln=line1, x=[], y=[]),
    frames=np.linspace(0, 2*np.pi, 128),
    init_func=init, blit=True)

plt.show()

第三种方法是使用闭包来构建所需的艺术家和函数。第四种方法是创建一个类。

示例#

ArtistAnimation#

示例#

Writer 类#

Inheritance diagram of matplotlib.animation.FFMpegFileWriter, matplotlib.animation.FFMpegWriter, matplotlib.animation.ImageMagickFileWriter, matplotlib.animation.ImageMagickWriter, matplotlib.animation.PillowWriter, matplotlib.animation.HTMLWriter

提供的写入器分为几个大类。

Pillow 写入器依赖 Pillow 库来写入动画,将所有数据保存在内存中。

HTML 写入器生成基于 JavaScript 的动画。

HTMLWriter

用于基于JavaScript的HTML电影的编写器。

基于管道的写入器通过管道将捕获的帧流式传输到外部进程。基于管道的变体往往性能更高,但可能并非在所有系统上都适用。

FFMpegWriter

基于管道的 ffmpeg 写入器。

ImageMagickWriter

基于管道的动画GIF写入器。

基于文件的写入器为每个帧保存临时文件,这些文件最终会被拼接成一个单一文件。尽管速度较慢,但这些写入器更容易调试。

FFMpegFileWriter

基于文件的 ffmpeg 写入器。

ImageMagickFileWriter

基于文件的动画 GIF 写入器。

写入器类提供了一种从相同的底层 Figure 抓取连续帧的方法。它们都提供了三个必须按顺序调用的方法:

  • setup 准备写入器(例如,打开一个管道)。基于管道和基于文件的写入器在调用 setup() 时需要不同的参数。

  • grab_frame 可以按需多次调用,以一次捕捉一帧。

  • finish 完成电影并将其输出文件写入磁盘。

示例:

moviewriter = MovieWriter(...)
moviewriter.setup(fig, 'my_movie.ext', dpi=100)
for j in range(n):
    update_figure(j)
    moviewriter.grab_frame()
moviewriter.finish()

如果直接使用写入器类(而不是通过 Animation.save),强烈建议使用 saving 上下文管理器:

with moviewriter.saving(fig, 'myfile.mp4', dpi=100):
    for j in range(n):
        update_figure(j)
        moviewriter.grab_frame()

以确保在必要时执行设置和清理。

示例#

辅助类#

动画基类#

Animation

动画的基类。

TimedAnimation

Animation 子类用于基于时间的动画。

写作者注册表#

提供了一个模块级别的注册表,用于在写入器的名称和类之间进行映射,以便可以将字符串传递给 Animation.save 而不是写入器实例。

MovieWriterRegistry

按人类可读名称分类的可用写入器类注册表。

Writer 基类#

为了减少代码重复,基类

AbstractMovieWriter

编写电影的抽象基类,提供通过调用 grab_frame 抓取帧的方法。

MovieWriter

编写电影的基类。

FileMovieWriter

MovieWriter 用于写入单个文件并在最后进行拼接。

和混入

FFMpegBase

FFMpeg 输出的 Mixin 类。

ImageMagickBase

ImageMagick 输出的 Mixin 类。

提供。

查看源代码以了解如何轻松实现新的 MovieWriter 类。