matplotlib使用FuncAnimation生成动画中func、frames、fargs参数传递思考

博客详细介绍了如何使用matplotlib的FuncAnimation类生成动画,包括仅使用frames参数的单参数回调函数实现和使用frames及fargs参数的多参数回调函数实现方式。通过实例代码展示了如何在动画中更新散点图,并解释了FuncAnimation工作原理,强调了frames参数如何生成可迭代对象以及fargs参数如何传递额外参数给回调函数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

FuncAnimationmatplotlib生成动画的常用类,它的工作原理就是不断调用参数func对应的函数生成动画。
FuncAnimation构造方法中关键的三个参数为funcframesfargs

  • func:对于逐帧动画来说就是每一帧的生成方法。
  • frames:暂且不管它在底层如何实现,最终将生成一个可迭代对象,用于每次向func生成的每一帧传递一个值。
  • fargs:除frames之外需要向func传递的参数。

在查找使用FuncAnimation生成动画的资料过程中,发现大多数案例在编写回调函数func时,一般都只构造1个参数,这样fargs参数就用不到了,如果回调函数有多个参数怎么实现呢。

只使用frames参数不使用fargs参数的实现方法(回调函数只有一个参数)

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

t = np.linspace(0, 6, 100)
x = 16 * np.sin(t) ** 3
y = 13 * np.cos(t) - 5 * np.cos(2 * t) - 2 * np.cos(3 * t) - np.cos(4 * t)
data=[i for i in zip(x,y)]

def plot_love(data):
    x, y = data
    plt.scatter(x, y, 60, c="r", alpha=0.7, marker=r"$\heartsuit$")

fig=plt.figure(figsize=(5, 3), dpi=100)
plt.axis("off")
animator = animation.FuncAnimation(fig, plot_love, frames=data, interval=80)
animator.save("love.gif", writer='pillow')

在这个案例中:
plot_love就是FuncAnimation构造方法中的func参数,也即回调函数。
frames参数的取值是datadata是一个构造好的二元组-列表,plot_love每次调用从中取一个值。

使用fargs参数的实现方法(回调函数多个参数)

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

t = np.linspace(0, 6, 100)
x = 16 * np.sin(t) ** 3
y = 13 * np.cos(t) - 5 * np.cos(2 * t) - 2 * np.cos(3 * t) - np.cos(4 * t)

def plot_love(num,x,y):
    plt.scatter(x[:num],y[:num],60, c="r", alpha=0.7, marker=r"$\heartsuit$")

fig=plt.figure(figsize=(5, 3), dpi=100)
plt.axis("off")

animator = animation.FuncAnimation(fig, plot_love, frames=len(t), fargs=(x,y), interval=80)
animator.save("love0.gif", writer='pillow')

在这个案例中:
plot_love就是FuncAnimation构造方法中的func参数,也即回调函数,这里有3个参数。
frames参数的取值是len(t)len(t)会用于构造成一个长度为len(t)序列,依次将元素传递给回调函数plot_love中的参数num
fargs参数取值为(x,y),在传递给回调函数plot_love时解包为x,y

原理分析

FuncAnimation类的文档中可知,func参数每帧调用一次,第一个参数frameframes参数中的下一个元素,也可以说frames是一个可迭代对象。
因此,在第一个案例中,frames的参数值是一个值序列,每调用一次回调函数就从中取一个值,取值过程不用我们干预。
在第二个案例中,frames的值是一个整数,但是在底层上,会利用range()函数生成一个可迭代对象,作为第一个参数传递给回调函数,机制同第一个案例。fargs作为可变参数传递给回调函数,该参数没有类似frames参数的取值机制,因此,传递过去的值就是对象本身。

func : callable
        The function to call at each frame.  The first argument will
        be the next value in *frames*.   Any additional positional
        arguments can be supplied via the *fargs* parameter.

        The required signature is::

            def func(frame, *fargs) -> iterable_of_artists

以下是FuncAnimation类的文档字符串。

def __init__(self, fig, func, frames=None, init_func=None, fargs=None,
                 save_count=None, *, cache_frame_data=True, **kwargs):

    """
    Makes an animation by repeatedly calling a function *func*.

    Parameters
    ----------
    fig : `~matplotlib.figure.Figure`
        The figure object used to get needed events, such as draw or resize.

    func : callable
        The function to call at each frame.  The first argument will
        be the next value in *frames*.   Any additional positional
        arguments can be supplied via the *fargs* parameter.

        The required signature is::

            def func(frame, *fargs) -> iterable_of_artists

        If ``blit == True``, *func* must return an iterable of all artists
        that were modified or created. This information is used by the blitting
        algorithm to determine which parts of the figure have to be updated.
        The return value is unused if ``blit == False`` and may be omitted in
        that case.

    frames : iterable, int, generator function, or None, optional
        Source of data to pass *func* and each frame of the animation

        - If an iterable, then simply use the values provided.  If the
          iterable has a length, it will override the *save_count* kwarg.

        - If an integer, then equivalent to passing ``range(frames)``

        - If a generator function, then must have the signature::

             def gen_function() -> obj

        - If *None*, then equivalent to passing ``itertools.count``.

        In all of these cases, the values in *frames* is simply passed through
        to the user-supplied *func* and thus can be of any type.

    init_func : callable, optional
        A function used to draw a clear frame. If not given, the results of
        drawing from the first item in the frames sequence will be used. This
        function will be called once before the first frame.

        The required signature is::

            def init_func() -> iterable_of_artists

        If ``blit == True``, *init_func* must return an iterable of artists
        to be re-drawn. This information is used by the blitting algorithm to
        determine which parts of the figure have to be updated.  The return
        value is unused if ``blit == False`` and may be omitted in that case.

    fargs : tuple or None, optional
        Additional arguments to pass to each call to *func*.

    save_count : int, default: 100
        Fallback for the number of values from *frames* to cache. This is
        only used if the number of frames cannot be inferred from *frames*,
        i.e. when it's an iterator without length or a generator.

    interval : int, default: 200
        Delay between frames in milliseconds.

    repeat_delay : int, default: 0
        The delay in milliseconds between consecutive animation runs, if
        *repeat* is True.

    repeat : bool, default: True
        Whether the animation repeats when the sequence of frames is completed.

    blit : bool, default: False
        Whether blitting is used to optimize drawing.  Note: when using
        blitting, any animated artists will be drawn according to their zorder;
        however, they will be drawn on top of any previous artists, regardless
        of their zorder.

    cache_frame_data : bool, default: True
        Whether frame data is cached.  Disabling cache might be helpful when
        frames contain large objects.
    """
### 使用 Matplotlib 的 `FuncAnimation` 创建动画 创建动态图像对于数据可视化来说非常重要,尤其是在展示随时间变化的数据时。通过使用 `matplotlib.animation.FuncAnimation` 可以轻松实现这一目标。 #### 导入所需模块 为了构建动画,首先需要导入几个重要的 Python 库: ```python import numpy as np import matplotlib.pyplot as plt from matplotlib.animation import FuncAnimation ``` 这些库提供了处理数值计算以及绘图的功能[^1]。 #### 初始化图形对象 定义画布并设置坐标轴范围,这一步骤确保了每次更新帧之前都有一个干净的状态来绘制新的点或线段。 ```python fig, ax = plt.subplots() xdata, ydata = [], [] ln, = plt.plot([], [], 'ro') ``` 这里初始化了一个红色圆圈标记(`'ro'`)的线条(ln),它将在后续被用来表示移动中的点[^3]。 #### 设置初始状态函数 此部分用于设定图表的基础属性,比如 X 和 Y 轴的最大最小值等。 ```python def init(): ax.set_xlim(0, 2 * np.pi) ax.set_ylim(-1, 1) return ln, ``` 这段代码设置了横坐标的取值区间是从 \(0\) 到 \(2\pi\) ,纵坐标则限定在 \([-1,+1]\)之间。 #### 定义每一帧的内容 这是核心逻辑所在的地方,在每一轮迭代中都会调用这个方法去改变所要显示的对象的位置或其他特性。 ```python def update(frame): xdata.append(frame) ydata.append(np.sin(frame)) ln.set_data(xdata, ydata) return ln, ``` 在这个例子里面,随着 frame 参数的变化(即时间推移),会不断向列表 `xdata`, `ydata` 中添加新元素,并且调整线条 `ln` 所代表路径上的所有点位置,从而形成一条正弦波形轨迹。 #### 构建动画实例 最后一步就是利用上述组件构造出完整的动画效果。 ```python ani = FuncAnimation(fig, update, frames=np.linspace(0, 2 * np.pi, 128), init_func=init, blit=True) plt.show() ``` 此处指定了总共有多少个不同的画面 (`frames`) 组成整个视频序列;还设定了启动前执行一次初始化操作(init_func); 同时开启了优化选项(blit=True),使得只重绘那些确实发生了变动的部分,提高效率。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值