python-animation

2023-03-10 16:03:55 浏览数 (1)

matplotlib.animationmatplotlib 的动态图库,本文记录使用方法。

用法介绍

  • matplotlib 是 Python 中常用的绘图工具,其中的animation 可以绘制动画
  • 官方文档:https://matplotlib.org/stable/api/_as_gen/matplotlib.animation.FuncAnimation.html#matplotlib.animation.FuncAnimation
语法

使用函数:matplotlib.animation.FuncAnimation

代码语言:javascript复制
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

0 人点赞