注意
转到末尾以下载完整的示例代码。
使用 Matplotlib 创建动画#
Matplotlib 在其绘图功能的基础上,还提供了一个接口,用于使用 animation
模块生成动画。动画是帧的序列,其中每帧对应于 Figure
上的一个图。本教程涵盖了创建此类动画的一般指南和可用的不同选项。更多信息可在 API 说明中找到:animation
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.animation as animation
动画类#
Matplotlib 中的动画过程可以从两种不同的方式来理解:
FuncAnimation
: 为第一帧生成数据,然后为每一帧修改此数据以创建动画图。ArtistAnimation
: 生成一个 artist 列表(可迭代对象),这些 artist 将在动画的每一帧中绘制。
FuncAnimation
在速度和内存方面更高效,因为它只绘制一次 artist,然后对其进行修改。另一方面,ArtistAnimation
更灵活,因为它允许任何 artist 可迭代对象按序列进行动画制作。
FuncAnimation
#
FuncAnimation
类允许我们通过传递一个迭代修改绘图数据的函数来创建动画。这通过使用各种 Artist
上的 setter 方法(例如:Line2D
、PathCollection
等)来实现。一个典型的 FuncAnimation
对象接受一个我们想要动画的 Figure
和一个修改图上绘制数据的函数 func。它使用 frames 参数来确定动画的长度。interval 参数用于确定绘制两帧之间的时间(以毫秒为单位)。使用 FuncAnimation
进行动画通常需要以下步骤:
像在静态绘图中一样绘制初始图形。将所有由绘图函数创建的 artist 保存到变量中,以便您可以在动画函数中稍后访问和修改它们。
创建一个动画函数,用于更新给定帧的 artist。通常,这会调用 artist 的
set_*
方法。创建一个
FuncAnimation
对象,并传入Figure
和动画函数。使用以下方法之一保存或显示动画:
pyplot.show
在窗口中显示动画Animation.to_html5_video
创建一个 HTML<video>
标签Animation.to_jshtml
创建带有交互式 JavaScript 动画控件的 HTML 代码Animation.save
将动画保存到文件
下表显示了一些绘图方法、它们返回的 artist 以及一些常用的 set_*
方法,这些方法用于更新底层数据。虽然更新数据是动画中最常见的操作,但您也可以更新其他方面,例如颜色或文本位置。
绘图方法 |
Artist |
数据设置方法 |
---|---|---|
|
||
|
||
本教程的范围不包括涵盖所有类型 artist 的 set 方法,但可以在它们各自的文档中找到。以下是 Axes.scatter
和 Axes.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
#
如果数据存储在各种不同的 artist 上,可以使用 ArtistAnimation
来生成动画。然后,这个 artist 列表会被逐帧转换为动画。例如,当我们使用 Axes.barh
绘制条形图时,它会为每个条形和误差条创建多个 artist。要更新绘图,需要单独更新容器中的每个条形并重新绘制它们。相反,可以使用 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、ffmpeg、imagemagick)保存到磁盘。并非所有写入器都支持所有视频格式。主要有 4 种类型的写入器:
PillowWriter
- 使用 Pillow 库创建动画。HTMLWriter
- 用于创建基于 JavaScript 的动画。基于管道的写入器 -
FFMpegWriter
和ImageMagickWriter
是基于管道的写入器。这些写入器将每帧通过管道传输到实用程序(ffmpeg / imagemagick),然后由该实用程序将所有帧拼接在一起以创建动画。基于文件的写入器 -
FFMpegFileWriter
和ImageMagickFileWriter
是基于文件的写入器的示例。这些写入器比基于管道的替代品慢,但对于调试更有用,因为它们在将每帧拼接成动画之前会将其保存到文件中。
保存动画#
写入器 |
支持的格式 |
---|---|
.gif, .apng, .webp |
|
.htm, .html, .png |
|
所有 ffmpeg 支持的格式: |
|
所有 imagemagick 支持的格式: |
要使用任何写入器保存动画,我们可以使用 animation.Animation.save
方法。它接受我们想要保存的动画的 文件名 和 写入器,写入器可以是字符串或写入器对象。它还接受一个 fps 参数。此参数与 FuncAnimation
或 ArtistAnimation
使用的 interval 参数不同。fps 决定了**保存**的动画使用的帧率,而 interval 决定了**显示**的动画使用的帧率。
下面是一些展示如何使用不同写入器保存动画的示例。
Pillow 写入器
HTML 写入器
FFMpegWriter
Imagemagick 写入器
(apng 需要 extra_args
来将文件大小减少约 10 倍)
请注意,ffmpeg 和 imagemagick 需要单独安装。获取 ffmpeg 的跨平台方法是安装 imageio_ffmpeg
PyPI 包,然后设置 rcParams["animation.ffmpeg_path"] = imageio_ffmpeg.get_ffmpeg_exe()
。
脚本总运行时间: (0 分 6.098 秒)