使用 Matplotlib 的动画#

基于其绘图功能,Matplotlib 还提供了一个使用 animation 模块生成动画的接口。动画是一系列帧,其中每一帧对应于 Figure 上的一个图。本教程涵盖了创建此类动画的一般指南以及可用的不同选项。更多信息可在 API 描述中找到:animation

import matplotlib.pyplot as plt
import numpy as np

import matplotlib.animation as animation

动画类#

在 Matplotlib 中,动画过程可以以两种不同的方式来考虑:

  • FuncAnimation:生成第一帧的数据,然后修改每一帧的数据以创建动画图。

  • ArtistAnimation: 生成一个艺术家列表(可迭代对象),这些艺术家将在动画的每一帧中绘制。

FuncAnimation 在速度和内存方面更高效,因为它只绘制一次艺术家,然后对其进行修改。另一方面,ArtistAnimation 更灵活,因为它允许任何艺术家可迭代对象按顺序进行动画处理。

FuncAnimation#

FuncAnimation 类允许我们通过传递一个函数来创建动画,该函数迭代地修改图的数据。这是通过在各种 Line2DPathCollection 等)上使用 setter 方法实现的。一个常见的 FuncAnimation 对象需要一个我们想要动画的 Figure 和一个修改图中数据绘制的函数 func。它使用 frames 参数来确定动画的长度。interval 参数用于确定绘制两帧之间的时间(以毫秒为单位)。使用 FuncAnimation 进行动画通常需要以下步骤:

  1. 像在静态图中一样绘制初始图形。将由绘图函数返回的所有创建的艺术家保存在变量中,以便您可以在动画函数中稍后访问和修改它们。

  2. 创建一个动画函数,用于更新给定帧的艺术元素。通常,这会调用艺术元素的 set_* 方法。

  3. 创建一个 FuncAnimation,传递 Figure 和动画函数。

  4. 使用以下方法之一保存或显示动画:

下表展示了几种绘图方法、它们返回的艺术家以及一些常用的 set_* 方法,这些方法用于更新底层数据。虽然更新数据是动画中最常见的操作,但你也可以更新其他方面,如颜色或文本位置。

涵盖所有类型艺术家的设置方法超出了本教程的范围,但可以在各自的文档中找到。以下是 Axes.scatterAxes.plot 中使用的此类更新方法的示例。

fig, ax = plt.subplots()
t = np.linspace(0, 3, 40)
g = -9.81
v0 = 12
z = g * t**2 / 2 + v0 * t

v02 = 5
z2 = g * t**2 / 2 + v02 * t

scat = ax.scatter(t[0], z[0], c="b", s=5, label=f'v0 = {v0} m/s')
line2 = ax.plot(t[0], z2[0], label=f'v0 = {v02} m/s')[0]
ax.set(xlim=[0, 3], ylim=[-4, 10], xlabel='Time [s]', ylabel='Z [m]')
ax.legend()


def update(frame):
    # for each frame, update the data stored on each artist.
    x = t[:frame]
    y = z[:frame]
    # update the scatter plot:
    data = np.stack([x, y]).T
    scat.set_offsets(data)
    # update the line plot:
    line2.set_xdata(t[:frame])
    line2.set_ydata(z2[:frame])
    return (scat, line2)


ani = animation.FuncAnimation(fig=fig, func=update, frames=40, interval=30)
plt.show()

ArtistAnimation#

ArtistAnimation 可以用于生成动画,如果数据存储在不同的艺术家上。这个艺术家列表随后被逐帧转换成动画。例如,当我们使用 Axes.barh 绘制条形图时,它会为每个条形和误差条创建多个艺术家。要更新图表,需要逐一更新容器中的每个条形并重新绘制它们。相反,animation.ArtistAnimation 可以用于逐帧绘制每个帧,然后将它们拼接在一起形成动画。条形竞赛是一个简单的例子。

fig, ax = plt.subplots()
rng = np.random.default_rng(19680801)
data = np.array([20, 20, 20, 20])
x = np.array([1, 2, 3, 4])

artists = []
colors = ['tab:blue', 'tab:red', 'tab:green', 'tab:purple']
for i in range(20):
    data += rng.integers(low=0, high=10, size=data.shape)
    container = ax.barh(x, data, color=colors)
    artists.append(container)


ani = animation.ArtistAnimation(fig=fig, artists=artists, interval=400)
plt.show()

动画编剧#

动画对象可以使用各种多媒体写入器(例如:Pillow、ffpmegimagemagick)保存到磁盘。并非所有视频格式都受所有写入器支持。主要有4种写入器类型:

  • PillowWriter - 使用 Pillow 库来创建动画。

  • HTMLWriter - 用于创建基于JavaScript的动画。

  • 基于管道的写入器 - FFMpegWriterImageMagickWriter 是基于管道的写入器。这些写入器将每一帧通过管道传输到实用程序(ffmpeg / imagemagick),然后将其全部拼接在一起以创建动画。

  • 基于文件的写入器 - FFMpegFileWriterImageMagickFileWriter 是基于文件的写入器的例子。这些写入器比基于管道的替代方案慢,但在调试时更有用,因为它们在将每一帧拼接成动画之前将其保存为文件。

保存动画#

作家

支持的格式

PillowWriter

.gif, .apng, .webp

HTMLWriter

.htm, .html, .png

所有由 ffmpeg 支持的格式:ffmpeg -formats

所有受 imagemagick 支持的格式:magick -list format

要使用任何写入器保存动画,我们可以使用 animation.Animation.save 方法。它需要我们想要保存动画的 文件名写入器,后者可以是一个字符串或写入器对象。它还需要一个 fps 参数。这个参数与 FuncAnimationArtistAnimation 使用的 interval 参数不同。fps 决定了 保存 动画使用的帧率,而 interval 决定了 显示 动画使用的帧率。

以下是一些示例,展示了如何使用不同的写入器保存动画。

Pillow 作者:

ani.save(filename="/tmp/pillow_example.gif", writer="pillow")
ani.save(filename="/tmp/pillow_example.apng", writer="pillow")

HTML 写作者:

ani.save(filename="/tmp/html_example.html", writer="html")
ani.save(filename="/tmp/html_example.htm", writer="html")
ani.save(filename="/tmp/html_example.png", writer="html")

FFMpegWriter:

ani.save(filename="/tmp/ffmpeg_example.mkv", writer="ffmpeg")
ani.save(filename="/tmp/ffmpeg_example.mp4", writer="ffmpeg")
ani.save(filename="/tmp/ffmpeg_example.mjpeg", writer="ffmpeg")

Imagemagick 写入器:

ani.save(filename="/tmp/imagemagick_example.gif", writer="imagemagick")
ani.save(filename="/tmp/imagemagick_example.webp", writer="imagemagick")
ani.save(filename="apng:/tmp/imagemagick_example.apng",
         writer="imagemagick", extra_args=["-quality", "100"])

(对于 apngextra_args 是用来将文件大小减少约10倍)

脚本总运行时间: (0 分钟 2.696 秒)

由 Sphinx-Gallery 生成的图库