matplotlib.animation
是matplotlib
的动态图库,本文记录使用方法。
用法介绍
-
matplotlib
是 Python 中常用的绘图工具,其中的animation
可以绘制动画 - 官方文档:https://matplotlib.org/stable/api/_as_gen/matplotlib.animation.FuncAnimation.html#matplotlib.animation.FuncAnimation
语法
使用函数:matplotlib.animation.FuncAnimation
matplotlib.animation.FuncAnimation(fig, func, frames=None, init_func=None, fargs=None, save_count=None, *, cache_frame_data=True, **kwargs)
- 参数说明:
| 参数 | 类型 | 含义 |
| ----------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
| **fig** | [`Figure`](https://matplotlib.org/stable/api/figure_api.html#matplotlib.figure.Figure) | 用于获取所需事件(如绘制或调整大小)的图形对象。 |
| **func** | callable | 每帧上调用的函数,第一个参数是每帧图像的编号。其他参数可以使用 `funtools.part` 或通过 `fargs` 参数提供。返回值为可遍历的绘图对象:<br />`def func(frame, *fargs) -> iterable_of_artists` |
| **frames** | iterable, int, generator function, or None, optional | 传递 func 和每帧动画的数据源,可以是列表,也可以是数字 (替换为 `range(frames)`) |
| **init_func(callable)** | callable, optional | 一种用于绘制清晰框架的函数。如果没有给出,将使用从帧序列中的第一个项目绘制的结果。这个函数将在第一帧之前调用一次。 |
| **fargs** | tuple or None, optional | 传递给每次调用 func 的附加参数。注意:使用 `functools.partial` 优于 `fargs`。 |
| **save_count** | int, default: 100 | 从帧到缓存的值数的后备。只有当无法从帧中推断出帧的数量时才会使用,例如,当它是一个没有长度的迭代器或生成器时。 |
| **interval** | int, default: 200 | 帧之间的延迟,以毫秒为单位。 |
| **repeat_delay** | int, default: 0 | 如果 repeat 为 True,则连续动画运行之间以毫秒为单位的延迟。 |
| **repeat** | bool, default: True | 当帧序列完成时,动画是否重复。 |
| **blit** | bool, default: False | 是否优化绘图。 |
| **cache_frame_data** | bool, default: True | 是否缓存帧数据。当帧包含大对象时,禁用缓存可能会有帮助。 |
#### 方法
| 方法 | 说明 |
| ------------------------------------------------ | ------------------------------------ |
| `__init__` | 初始化对象。 |
| `new_frame_seq()` | 返回一个新的帧序列信息。 |
| `pause()` | 暂停动画。 |
| `resume()` | 继续动画。 |
| `save(filename[, writer, fps, dpi, codec, ...])` | 通过绘制每一帧将动画保存为电影文件。 |
| `to_html5_video([embed_limit])` | 将动画转换为 HTML5 < video > 标记。 |
| `to_jshtml([fps, embed_frames, default_mode])` | 生成的 HTML 动画。 |
- 通过 `plt.show()` 可以展示动画过程。
- `save` 函数参数 :
| 参数 | 类型 | 描述 |
| --------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
| **filename** | str | 输出文件名,例如: `a.gif`, `b.mp4` |
| **writer** | MovieWriter or str, default: rcParams["animation.writer"] (default: 'ffmpeg') | 要使用的 MovieWriter 实例或标识要使用的类的键,如“ ffmpeg”。 |
| **fps** | int, optional | 电影帧速率(每秒)。如果没有设置,帧速率从动画的帧间隔。 |
| **dpi** | float, default: rcParams["savefig.dpi"] (default: 'figure') | 控制电影帧的每英寸点数。加上人物的尺寸(英寸) ,这可以控制电影的大小。 |
| **codec** | str, default: rcParams["animation.codec"] (default: 'h264'). | 要使用的视频编解码器。 |
| **bitrate** | int, default: rcParams["animation.bitrate"] (default: -1) | 电影的比特率,以千比特每秒为单位。更高的值意味着更高质量的电影,但增加文件大小。值 -1允许基础电影编码器选择比特率。 |
| **extra_args** | list of str or None, optional | 传递给基础电影编码器的额外命令行参数。 |
| **metadata** | dict[str, str], default: {} | 输出文件中要包含的元数据的键和值的字典。一些可能有用的关键字包括: 标题、艺术家、类型、主题、版权、 srcform、评论。 |
| **extra_anim** | list, default: [] | 应包含在保存的电影文件中的其他 Animation 对象。 |
| **savefig_kwargs** | dict, default: {} | 传递给用于保存各个帧的每个 savefig 调用的关键字参数。 |
| **progress_callback** | function, optional | 一个回调函数,每个帧都会调用该函数来通知保存进度。它必须有签名 |
### 官方示例
- 官方给出了很多使用示例:https://matplotlib.org/stable/gallery/index.html
- 取其中一个稍作修改展示出来:
```python
from numpy import sin, cos
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from collections import deque
G = 9.8 # acceleration due to gravity, in m/s^2
L1 = 1.0 # length of pendulum 1 in m
L2 = 1.0 # length of pendulum 2 in m
L = L1 L2 # maximal length of the combined pendulum
M1 = 1.0 # mass of pendulum 1 in kg
M2 = 1.0 # mass of pendulum 2 in kg
t_stop = 8 # how many seconds to simulate
history_len = 500 # how many trajectory points to display
def derivs(t, state):
dydx = np.zeros_like(state)
dydx[0] = state[1]
delta = state[2] - state[0]
den1 = (M1 M2) * L1 - M2 * L1 * cos(delta) * cos(delta)
dydx[1] = ((M2 * L1 * state[1] * state[1] * sin(delta) * cos(delta)
M2 * G * sin(state[2]) * cos(delta)
M2 * L2 * state[3] * state[3] * sin(delta)
- (M1 M2) * G * sin(state[0]))
/ den1)
dydx[2] = state[3]
den2 = (L2/L1) * den1
dydx[3] = ((- M2 * L2 * state[3] * state[3] * sin(delta) * cos(delta)
(M1 M2) * G * sin(state[0]) * cos(delta)
- (M1 M2) * L1 * state[1] * state[1] * sin(delta)
- (M1 M2) * G * sin(state[2]))
/ den2)
return dydx
# create a time array from 0..t_stop sampled at 0.02 second steps
dt = 0.01
t = np.arange(0, t_stop, dt)
# th1 and th2 are the initial angles (degrees)
# w10 and w20 are the initial angular velocities (degrees per second)
th1 = 120.0
w1 = 0.0
th2 = -10.0
w2 = 0.0
# initial state
state = np.radians([th1, w1, th2, w2])
# integrate the ODE using Euler's method
y = np.empty((len(t), 4))
y[0] = state
for i in range(1, len(t)):
y[i] = y[i - 1] derivs(t[i - 1], y[i - 1]) * dt
# A more accurate estimate could be obtained e.g. using scipy:
#
# y = scipy.integrate.solve_ivp(derivs, t[[0, -1]], state, t_eval=t).y.T
x1 = L1*sin(y[:, 0])
y1 = -L1*cos(y[:, 0])
x2 = L2*sin(y[:, 2]) x1
y2 = -L2*cos(y[:, 2]) y1
fig = plt.figure(figsize=(5, 4))
ax = fig.add_subplot(autoscale_on=False, xlim=(-L, L), ylim=(-L, 1.))
ax.set_aspect('equal')
ax.grid()
line, = ax.plot([], [], 'o-', lw=2)
trace, = ax.plot([], [], '.-', lw=1, ms=2)
time_template = 'time = %.1fs'
time_text = ax.text(0.05, 0.9, '', transform=ax.transAxes)
history_x, history_y = deque(maxlen=history_len), deque(maxlen=history_len)
def animate(i):
thisx = [0, x1[i], x2[i]]
thisy = [0, y1[i], y2[i]]
if i == 0:
history_x.clear()
history_y.clear()
history_x.appendleft(thisx[2])
history_y.appendleft(thisy[2])
line.set_data(thisx, thisy)
trace.set_data(history_x, history_y)
time_text.set_text(time_template % (i*dt))
return line, trace, time_text
ani = animation.FuncAnimation(
fig, animate, len(y), interval=dt*1000, blit=True)
ani.save('show.gif', writer='pillow', fps=10)
plt.show()
动画效果:
参考资料
- https://matplotlib.org/stable/api/_as_gen/matplotlib.animation.FuncAnimation.html#matplotlib.animation.FuncAnimation
- https://matplotlib.org/stable/gallery/index.html
- https://www.cnblogs.com/endlesscoding/p/10308111.html