matplotlib.animation#

动画#

在 Matplotlib 中创建实时动画最简单的方法是使用 Animation 类之一。

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

动画

动画的基类。

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)

当然,这省略了许多细节(例如当图形被调整大小或完全重绘时更新背景)。然而,这个极简示例有望让您了解 FuncAnimation 内部如何使用 init_funcfunc,以及“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#

示例#

写入器类#

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()

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

示例#

辅助类#

动画基类#

动画

动画的基类。

TimedAnimation

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

写入器注册表#

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

MovieWriterRegistry

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

写入器基类#

为减少代码重复,提供以下基类:

AbstractMovieWriter

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

MovieWriter

电影写入器的基类。

FileMovieWriter

用于写入单个文件并在最后拼接的 MovieWriter

和混入类:

FFMpegBase

FFMpeg 输出的混入类。

ImageMagickBase

ImageMagick 输出的混入类。

有关如何轻松实现新的 MovieWriter 类,请参阅源代码。