作者:刘兴禄,清华大学博士在读

参考视频: b站:https://www.bilibili.com/video/BV18i4y1T78J?p=1&share_medium=iphone&share_plat=ios&share_session_id=4635DEFA-A6BB-4EFE-A9E6-35EEECF1F02A&share_source=WEIXIN&share_tag=s_i&timestamp=1648641507&unique_k=kc2TFEZ

animation.FuncAnimation函数的基本使用

调用函数animation.FuncAnimation(fig, func, frames=None, init_func=None, fargs=None, save_count=None, *, cache_frame_data=True, **kwargs)来生成动态图。

其中关键参数解释如下:

  • fig: Figure对象
  • func: The function to call at each frame.,其实就是创建每一帧图像的函数。这个函数来决定每一帧的图像上显示什么内容。
  • frames:这个参数实际上就是定义一个帧的序列,比如[1, 2, 3, 4, 5]就是一共有5帧图像,分别编号为1–5。
  • init_func:是为了绘制初始的干净的图像的函数。比如,我们固定画布的坐标轴范围为 [ 0 , 100 ] [0, 100] [0,100]

其余函数的作用可以之后再继续探索。

尝试使用animation.FuncAnimation函数

我们在每一帧的更新函数update中只是打印出一些内容,可以使用下面的代码。

import matplotlib.pyplot as plt
from matplotlib import animation

fig, ax = plt.subplots()

# 定义更新函数
def update(frame):   # 帧
    print(frame)
    pass

# 调用生成动画的函数生成动图
ani = animation.FuncAnimation(
    fig=fig,
    func=update,
    frames=[1, 2, 3],
    init_func=None
)

plt.show()

上述代码的执行结果为:
在这里插入图片描述

D:\Develop\anaconda\python.exe F:/PycharmProjects/01-Python-Plot-Notes】/02_Plot_Animation.py
1
1
2
3
1
2
3
1
2
3
。。。

可以看到,函数func=update在一次一次被调用并执行。因此,func=update中的内容,确实是每一帧需要做的事情。

我们接下来做一个比较完整的例子。

使用animation.FuncAnimation函数生生动图或者视频:一个简单的完整例子

import matplotlib.pyplot as plt
from matplotlib import animation

fig, ax = plt.subplots()

# 定义存储数据的列表
xdata = []
ydata = []

# 接收line2D对象
line, = plt.plot(xdata, ydata, 'ro')


# 定义更新函数
def update(frame_ID):   # 帧
    """ 根据每一帧的ID: frame_ID来更新数据。这里由于是要一直连续画,因此需要apeend一下之后的数据"""
    
    print(frame_ID)

    xdata.append(frame_ID)
    ydata.append(frame_ID ** 2)

    line.set_data(xdata, ydata)

    return line,

# 调用生成动画的函数生成动图
ani = animation.FuncAnimation(
    fig=fig,
    func=update,
    frames=[1, 2, 3],
    init_func=None
)

plt.show()

但是这个会导致每次会的图片的坐标轴都变动。

在这里插入图片描述

因此,我们需要调整初始化图像的参数init_func。更改代码如下:

import matplotlib.pyplot as plt
from matplotlib import animation

fig, ax = plt.subplots()

# 定义存储数据的列表
xdata = []
ydata = []

# 接收line2D对象
line, = plt.plot(xdata, ydata, 'ro')


# 定义更新函数
def update(frame_ID):   # 帧
    """ 根据每一帧的ID: frame_ID来更新数据。这里由于是要一直连续画,因此需要apeend一下之后的数据"""

    # print(frame_ID)

    xdata.append(frame_ID)
    ydata.append(frame_ID ** 2)

    line.set_data(xdata, ydata)

    return line,


def init_figure():
    ax.set_xlim(0, 5)
    ax.set_ylim(0, 10)


# 调用生成动画的函数生成动图
ani = animation.FuncAnimation(
    fig=fig,
    func=update,
    frames=[1, 2, 3],
    init_func=init_figure,
    interval=1000   #  每隔多少时间生成一帧图像,单位是ms
)

# plt.show()   # 如果要保存视频和gif就不要show()

ani.save('ani_1.gif')
# ani.save('ani_1.mp4')

效果如下:

在这里插入图片描述

使用animation.FuncAnimation函数生生动图或者视频:线连续起来

ani.save('ani_1.mp4', writer='ffmpeg')函数还可以设置的参数:(下面也有完整的函数解释 )

  • save(self, filename, writer=None, fps=None, dpi=None, codec=None, bitrate=None, extra_args=None, metadata=None, extra_anim=None, savefig_kwargs=None, *, progress_callback=None)
  • writer:可选: pillow或者ffmpeg,但是一定要提前安装好相应的包
  • fps:帧率,就是一秒钟展示多少帧
  • dpi:像素
import matplotlib.pyplot as plt
from matplotlib import animation
import numpy as np

fig, ax = plt.subplots()

# 定义存储数据的列表
xdata = []
ydata = []

# 接收line2D对象
line, = plt.plot(xdata, ydata, 'ro')


# 定义更新函数
def update(frame_ID):   # 帧
    """ 根据每一帧的ID: frame_ID来更新数据。这里由于是要一直连续画,因此需要apeend一下之后的数据"""

    # print(frame_ID)

    xdata.append(frame_ID)
    ydata.append(frame_ID ** 2)

    line.set_data(xdata, ydata)

    return line,


def init_figure():
    ax.set_xlim(-1, 6)
    ax.set_ylim(-1, 30)


# 调用生成动画的函数生成动图
ani = animation.FuncAnimation(
    fig=fig,
    func=update,
    frames=np.linspace(0, 5, 100),    # [1, 2, 3]
    init_func=init_figure,
    interval=5,   #  每隔多少时间生成一帧图像,单位是ms
    repeat=True,   # 设置不重复,但是还是重复较好
)

# plt.show()   # 如果要保存视频和gif就不要show()

# ani.save('ani_1.gif', writer='pillow')
ani.save('ani_1.mp4', writer='ffmpeg')  # 注意,pillow现在似乎不能报错为mp4格式了,可以使用ffmpeg

在这里插入图片描述

下面是导出的视频:

在这里插入图片描述

animation.FuncAnimation函数的详解

class FuncAnimation(TimedAnimation)
 |  FuncAnimation(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.
 |  
 |  Method resolution order:
 |      FuncAnimation
 |      TimedAnimation
 |      Animation
 |      builtins.object
 |  
|  Methods defined here:
 |  
 |  __init__(self, fig, func, frames=None, init_func=None, fargs=None, save_count=None, *, cache_frame_data=True, **kwargs)
 |      Initialize self.  See help(type(self)) for accurate signature.
 |  
 |  new_frame_seq(self)
 |      Return a new sequence of frame information.
 |  
 |  new_saved_frame_seq(self)
 |      Return a new sequence of saved/cached frame information.
 |  

save()函数

 |  ----------------------------------------------------------------------
 |  Methods inherited from Animation:
 |  
 |  save(self, filename, writer=None, fps=None, dpi=None, codec=None, bitrate=None, extra_args=None, metadata=None, extra_anim=None, savefig_kwargs=None, *, progress_callback=None)
 |      Save the animation as a movie file by drawing every frame.
 |      
 |      Parameters
 |      ----------
 |      filename : str
 |          The output filename, e.g., :file:`mymovie.mp4`.
 |      
 |      writer : `MovieWriter` or str, default: :rc:`animation.writer`
 |          A `MovieWriter` instance to use or a key that identifies a
 |          class to use, such as 'ffmpeg'.
 |      
 |      fps : int, optional
 |          Movie frame rate (per second).  If not set, the frame rate from the
 |          animation's frame interval.
 |      
 |      dpi : float, default: :rc:`savefig.dpi`
 |          Controls the dots per inch for the movie frames.  Together with
 |          the figure's size in inches, this controls the size of the movie.
 |      
 |      codec : str, default: :rc:`animation.codec`.
 |          The video codec to use.  Not all codecs are supported by a given
 |          `MovieWriter`.
 |      
 |      bitrate : int, default: :rc:`animation.bitrate`
 |          The bitrate of the movie, in kilobits per second.  Higher values
 |          means higher quality movies, but increase the file size.  A value
 |          of -1 lets the underlying movie encoder select the bitrate.
 |      
 |      extra_args : list of str or None, optional
 |          Extra command-line arguments passed to the underlying movie
 |          encoder.  The default, None, means to use
 |          :rc:`animation.[name-of-encoder]_args` for the builtin writers.
 |      
 |      metadata : Dict[str, str], default {}
 |          Dictionary of keys and values for metadata to include in
 |          the output file. Some keys that may be of use include:
 |          title, artist, genre, subject, copyright, srcform, comment.
 |      
 |      extra_anim : list, default: []
 |          Additional `Animation` objects that should be included
 |          in the saved movie file. These need to be from the same
 |          `matplotlib.figure.Figure` instance. Also, animation frames will
 |          just be simply combined, so there should be a 1:1 correspondence
 |          between the frames from the different animations.
 |      
 |      savefig_kwargs : dict, default: {}
 |          Keyword arguments passed to each `~.Figure.savefig` call used to
 |          save the individual frames.
 |      
 |      progress_callback : function, optional
 |          A callback function that will be called for every frame to notify
 |          the saving progress. It must have the signature ::
 |      
 |              def func(current_frame: int, total_frames: int) -> Any
 |      
 |          where *current_frame* is the current frame number and
 |          *total_frames* is the total number of frames to be saved.
 |          *total_frames* is set to None, if the total number of frames can
 |          not be determined. Return values may exist but are ignored.
 |      
 |          Example code to write the progress to stdout::
 |      
 |              progress_callback =                    lambda i, n: print(f'Saving frame {i} of {n}')
 |      
 |      Notes
 |      -----
 |      *fps*, *codec*, *bitrate*, *extra_args* and *metadata* are used to
 |      construct a `.MovieWriter` instance and can only be passed if
 |      *writer* is a string.  If they are passed as non-*None* and *writer*
 |      is a `.MovieWriter`, a `RuntimeError` will be raised.
 |  
 |  to_html5_video(self, embed_limit=None)
 |      Convert the animation to an HTML5 ``<video>`` tag.
 |      
 |      This saves the animation as an h264 video, encoded in base64
 |      directly into the HTML5 video tag. This respects :rc:`animation.writer`
 |      and :rc:`animation.bitrate`. This also makes use of the
 |      ``interval`` to control the speed, and uses the ``repeat``
 |      parameter to decide whether to loop.
 |      
 |      Parameters
 |      ----------
 |      embed_limit : float, optional
 |          Limit, in MB, of the returned animation. No animation is created
 |          if the limit is exceeded.
 |          Defaults to :rc:`animation.embed_limit` = 20.0.
 |      
 |      Returns
 |      -------
 |      str
 |          An HTML5 video tag with the animation embedded as base64 encoded
 |          h264 video.
 |          If the *embed_limit* is exceeded, this returns the string
 |          "Video too large to embed."
 |  
 |  to_jshtml(self, fps=None, embed_frames=True, default_mode=None)
 |      Generate HTML representation of the animation
 |  
 |  ----------------------------------------------------------------------
 |  Data descriptors inherited from Animation:
 |  
 |  __dict__
 |      dictionary for instance variables (if defined)
 |  
 |  __weakref__
 |      list of weak references to the object (if defined)
Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐