【我的Python可视化笔记-03】动图2:animation函数的使用
作者:刘兴禄,清华大学博士在读
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)