欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

matplotlib:利用FuncAnimation类生成简易逐帧动画

程序员文章站 2022-02-05 19:27:05
...

当前有效matplotlib版本为:3.4.1

概述

逐帧动画(Frame By Frame)是一种常见的动画形式,通过将不同的静止图像以一定时间间隔连续播放,因人类视觉暂停现象而获得动画的效果。

FuncAnimationmatplotlib生成逐帧动画的常用类,它的工作原理就是按照一定时间间隔不断调用参数func对应的函数生成动画。

FuncAnimation的继承关系如下:
matplotlib.animation.Animation→matplotlib.animation.TimedAnimation→matplotlib.animation.FuncAnimation

FuncAnimation类的签名为:class matplotlib.animation.FuncAnimation(fig, func, frames=None, init_func=None, fargs=None, save_count=None, *, cache_frame_data=True, **kwargs)

构造函数参数如下:

  • fig :承载动画的图形对象。 matplotlib.figure.Figure对象。必备参数。
  • func : 每一帧都需要调用的函数。可调用对象。必备参数。
    func 的签名如下为 def func(frame, *fargs) -> iterable_of_artists。第一个参数为frames参数传递过来的一个元素,剩余位置参数由fargs参数提供。
    如果 blit == Truefunc必须返回一个包含所有已创建或修改的可视化对象(artist)的可迭代对象。如果 blit == False ,返回值将被忽略。
  • frames :用于向func生成的每一帧传递一个值。可迭代对象,整数,生成器或None,可选参数。
    • 如果值为可迭代对象,直接使用可迭代对象。如果可迭代对象长度固定,将会覆盖save_count参数。
    • 如果值为整数,相当于传递range(frames)
    • 如果值为生成器,生成器的签名要求为def gen_function() -> obj
    • 如果值为None,相当于传递 itertools.count
  • init_func : 用于初始化帧的函数,在生成第1帧之前,会调用一次该函数。可调用对象。可选参数。如果不提供改参数, 将使用frames参数中的第一个元素的绘制结果。该参数的签名要求为def init_func() -> iterable_of_artists,除了参数,其余要求与func 参数类似。
  • fargs : 传递给func的附加参数。元组或None。可选参数。
  • save_count : 用于缓存frames值的数量,该参数只用于frames值数量不能推断出的情况。整数。默认值为100
  • interval:帧之间的间隔毫秒数。整数。默认值为200
  • repeat_delay:当repeatTrue时生效。即动画重复执行的间隔毫秒数。当整数。默认值为0
  • repeat :当帧序列执行一次之后是否重复执行。布尔值。默认值为True
  • blit: 是否采用按叠放次序(zorder)优化绘图模式。布尔值。默认值为False
  • cache_frame_data :每帧数据是否被缓存。布尔值。默认值为True

FuncAnimation类继承了matplotlib.animation.Animation类的pauseresume方法,可实现动画的暂停和继续功能。

案例1:动态绘制sin曲线

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


fig, ax = plt.subplots()
# 构造空线条
line, = ax.plot([], [])
# 构造线条数据结构
xdata, ydata = [], []
# 设置坐标轴刻度范围
ax.set_ylim(-1.1, 1.1)
ax.set_xlim(0, 50)

# 动画循环一次后进行初始化,清空数据
def init():
    del xdata[:]
    del ydata[:]
    line.set_data(xdata, ydata)
    return line,

# 控制每帧画面如何绘制
def update(x):
    y = np.sin(x)
    xdata.append(x)
    ydata.append(y)
    xmin, xmax = ax.get_xlim()
    line.set_data(xdata, ydata)
    fig.canvas.draw()
    return line,

ani = animation.FuncAnimation(fig, update, 50, interval=10, init_func=init)

plt.show()

案例2:点击鼠标左键暂停/继续动画

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


fig, ax = plt.subplots()
# 构造空线条
line, = ax.plot([], [])
# 构造线条数据
n = 50
x = np.arange(n)
y = np.sin(x)
# 设置坐标轴刻度范围
ax.set_ylim(-1.1, 1.1)
ax.set_xlim(0, n)


# 控制每帧画面如何绘制
def update(i):
    line.set_data(x[:i], y[:i])
    return line,

ani = animation.FuncAnimation(fig, update, n, interval=10,)

# 事件处理
paused = False

def toggle_pause(event):
    global paused
    if paused:
        ani.resume()
    else:
        ani.pause()
    paused = not paused

fig.canvas.mpl_connect('button_press_event', toggle_pause)

plt.show()