Matplotlib 动画怎么制作?用Python实现动态图动画有啥技巧?

文章导读
Previous Quiz Next 动画 是一种视觉技术,通过一系列单独的帧创建运动图像。每帧代表时间上的一个特定时刻,当连续快速播放时,它们会产生运动的错觉。例如,常见的动画对象示例是 GIF。这里是一个例子 −
📋 目录
  1. Matplotlib 中的动画
  2. 创建动画
  3. 保存动画
A A

Matplotlib - 动画



Previous
Quiz
Next

动画 是一种视觉技术,通过一系列单独的帧创建运动图像。每帧代表时间上的一个特定时刻,当连续快速播放时,它们会产生运动的错觉。例如,常见的动画对象示例是 GIF。这里是一个例子 −

Animations Intro

动画的流行文件格式包括 GIF、APNG(Animated Portable Network Graphics)、mkv、mp4 等。

Matplotlib 中的动画

Matplotlib 提供了一个专用的模块来创建动画。在这种情况下,动画是一系列帧,每帧都与 Figure 上的一个图表相关联。

为了将动画功能集成到我们的工作环境中,我们可以使用以下命令导入专用模块 −

import matplotlib.animation as animation

创建动画

在 Matplotlib 中创建动画可以通过两种不同的方法实现。matplotlib.animation 模块为此目的提供了两个主要 class −

  • FuncAnimation
  • ArtistAnimation

FuncAnimation class

使用 FuncAnimation class 的方法是一种高效的方式,通过为每一帧修改图表的数据来创建动画。它允许我们通过传递一个用户定义的函数来创建动画,该函数迭代修改图表的数据。这个 class 涉及为初始帧生成数据,然后为每个后续帧修改这些数据。

示例 - FuncAnimation Class 的用法

此示例演示了使用 FuncAnimation class 来为正弦波图表创建动画,展示物体的运动。它还使用 Matplotlib animation 更新 X 轴值。

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

# 创建 figure 和 axis
fig, ax = plt.subplots(figsize=(7, 4))

# 生成 x 值 
x = np.arange(0, 2*np.pi, 0.01)

# 绘制初始正弦曲线
line, = ax.plot(x, np.sin(x))
ax.legend([r'$\sin(x)$'])

# 更新动画每一帧图表的函数
def update(frame):
   line.set_ydata(np.sin(x + frame / 50))
   ax.set_xlim(left=0, right=frame)
   return line

# 创建 FuncAnimation 对象
ani = animation.FuncAnimation(fig=fig, func=update, frames=40, interval=30)

# 显示输出
plt.show()
输出

上述示例产生以下输出 −

Animations Ex1

示例 - 动画 3D 曲面图

这是一个使用 FuncAnimation class 创建动画 3D 曲面图的另一个示例。

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

# 生成数据
N = 50
fps = 250
frn = 75
x = np.linspace(-2, 2, N + 1)
x, y = np.meshgrid(x, x)
zarray = np.zeros((N + 1, N + 1, frn))
f = lambda x, y, sig: 1 / np.sqrt(sig) * np.exp(-(x ** 2 + y ** 2) / sig ** 2)

# 创建数据数组
for i in range(frn):
   zarray[:, :, i] = f(x, y, 1.5 + np.sin(i * 2 * np.pi / frn))

# 更新图表函数
def change_plot(frame_number, zarray, plot):
   plot[0].remove()
   plot[0] = ax.plot_surface(x, y, zarray[:, :, frame_number], cmap="afmhot_r")

# 创建 figure 和 subplot
fig = plt.figure(figsize=(7, 4))
ax = fig.add_subplot(111, projection='3d')

# 初始图表
plot = [ax.plot_surface(x, y, zarray[:, :, 0], color='0.75', rstride=1, cstride=1)]

# 设置轴限制
ax.set_zlim(0, 1.1)

# 动画
ani = animation.FuncAnimation(fig, change_plot, frn, fargs=(zarray, plot), interval=1000 / fps)

# 关闭轴和网格
ax.axis('off')
ax.grid(False)

# 显示图表
plt.show()
输出

上述示例产生以下输出 −

Animations Ex5

ArtistAnimation

ArtistAnimation 是一种灵活的方法,适用于需要按序列动画化不同 artist 的场景。这种方法涉及生成一个 artist 列表(可迭代对象),以便在动画的每一帧中绘制它们。

示例 - ArtistAnimation Class 的用法

此示例演示了使用 ArtistAnimation class 创建动画。

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

# 创建 figure 和 axis
fig, ax = plt.subplots(figsize=(7,4))

# 定义函数
def f(x, y):
   return np.sin(x) + np.cos(y)

# 为函数生成 x 和 y 值
x = np.linspace(0, 2 * np.pi, 180)
y = np.linspace(0, 2 * np.pi, 100).reshape(-1, 1)

# ims 是一个列表的列表,每一行是当前帧中要绘制的 artist 列表
ims = []

# 为动画生成帧
for i in range(60):
   x += np.pi / 10
   y += np.pi / 30
   im = ax.imshow(f(x, y), animated=True)
   if i == 0:
      ax.imshow(f(x, y))  # 首先显示一个初始图像
   ims.append([im])

# 使用指定的 interval、blit 和 repeat_delay 创建 ArtistAnimation
ani = animation.ArtistAnimation(fig, ims, interval=50, blit=True, repeat_delay=1000)
# 显示动画
plt.show()
输出

上述代码生成以下结果 −

Animations Ex2

保存动画

可以使用不同的多媒体写入器将动画对象保存到磁盘上,例如 Pillow、ffmpeg 和 imagemagick。不过,需要注意的是,并非所有视频格式都得到每个写入器的支持。有四种主要的写入器类型:

  • PillowWriter
  • HTMLWriter
  • Pipe-based writers
  • File-based writers

PillowWriter

它使用 Pillow 库将动画保存为各种格式,例如 GIF、APNG 和 WebP。

Example - Usage of PillowWriter Class

以下示例演示了如何使用 PillowWriter 对散点图进行动画化并将其保存为 GIF。

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

# 生成数据
steps = 50
nodes = 100
positions = []
solutions = []

for i in range(steps):
   positions.append(np.random.rand(2, nodes))
   solutions.append(np.random.random(nodes))

# 创建图形和轴
fig, ax = plt.subplots(figsize=(7, 4))
marker_size = 50

# 更新动画每一帧图形的函数
def animate(i):
   fig.clear()
   ax = fig.add_subplot(111, aspect='equal', autoscale_on=False, xlim=(0, 1), ylim=(0, 1))
   ax.set_xlim(0, 1)
   ax.set_ylim(0, 1)
   s = ax.scatter(positions[i][0], positions[i][1], s=marker_size, c=solutions[i], cmap="RdBu_r", marker="o", edgecolor='black')

plt.grid(None)

# 创建 FuncAnimation 对象
ani = animation.FuncAnimation(fig, animate, interval=100, frames=range(steps))

# 使用 PillowWriter 将动画保存为 GIF
ani.save('animation.gif', writer='pillow')

如果您访问输出保存的文件夹,您将看到以下 GIF 文件 −

Output
Animation Ex3

HTMLWriter

HTMLWriter 用于创建基于 JavaScript 的动画,支持 HTML 和 PNG 格式。此写入器适用于在网页中嵌入动画。

Pipe-based writers

这些写入器使用外部工具如 FFMpegWriter 和 ImageMagickWriter 来创建动画。它们支持各种视频格式,帧通过管道传输到该工具,该工具将它们拼接在一起以创建动画。

File-based writers

基于文件的写入器(FFMpegFileWriter 和 ImageMagickFileWriter)速度稍慢,但具有在创建最终动画之前保存每一帧的优势。

Example - Enabling ffmpeg

以下示例展示了如何为 matplotlib.animation 正确启用 ffmpeg。此处创建了一个带有动画图像矩阵和动画 colorbar 的图表。

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from mpl_toolkits.axes_grid1 import make_axes_locatable

plt.rcParams["figure.figsize"] = [7.50, 3.50]
plt.rcParams["figure.autolayout"] = True
plt.rcParams['animation.ffmpeg_path'] = 'ffmpeg'

fig = plt.figure()
ax = fig.add_subplot(111)
div = make_axes_locatable(ax)
cax = div.append_axes('right', '5%', '5%')
data = np.random.rand(5, 5)
im = ax.imshow(data)
cb = fig.colorbar(im, cax=cax)
tx = ax.set_title('Frame 0')

cmap = ["copper", 'RdBu_r', 'Oranges', 'cividis', 'hot', 'plasma']

def animate(i):
   cax.cla()
   data = np.random.rand(5, 5)
   im = ax.imshow(data, cmap=cmap[i%len(cmap)])
   fig.colorbar(im, cax=cax)
   tx.set_text('Frame {0}'.format(i))

ani = animation.FuncAnimation(fig, animate, frames=10)
FFwriter = animation.FFMpegWriter()
ani.save('plot.mp4', writer=FFwriter)
Output

执行上述代码后,您将得到以下输出 −

animations_ex4