实现图形的动画效果
在 matplotlib 中,不仅可以绘制静态图形,也可以绘制动态图形。对于动态图形来说,我们称 之为动画或许会让读者更容易明白。绘制动画的方法主要有两种:一种是使用模块 animation 绘制动 画;另一种是调用模块 pyplot 的 API 绘制动画。下面,我们就分别通过实用案例加以讲解,以使读 者理解这两种方法的区别和联系。
一,使用模块 animation 绘制动画
一般而言,在绘制复杂动画时,主要借助模块 animation 来完成。下面,我们就详细介绍模块 animation 中的类 FuncAnimation 的使用方法。
1.代码示例
python
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.animation import FuncAnimation
fig, ax = plt.subplots(1, 1)
x = np.linspace(0, 2 * np.pi, 5000)
y = np.exp(-x) * np.cos(2 * np.pi * x)
line, = ax.plot(x, y, color="cornflowerblue", lw=3)
ax.set_ylim(-1.0, 1.0)
# to clear current frame
def init():
line.set_ydata([np.nan] * len(x))
return line,
# to update the data
def animate(data):
line.set_ydata(np.exp(-x) * np.cos(2 * np.pi * x + float(data) / 100))
return line,
# to call class FuncAnimation which connects animate and init
ani = FuncAnimation(
fig,
animate,
init_func=init,
frames=200,
interval=2,
blit=True)
# to save the animation
ani.save("mymovie.mp4", fps=20, writer="ffmpeg")
plt.show()
演示视频
2.代码讲解
<1>我们定义了两个函数 init()和 animate(),函数 init()的作用是在绘制下一帧动画画面之前 清空画布窗口中的当前动画画面,函数 animate()的作用是绘制每帧动画画面。这两个函数的返 回值"line"后面的符号","是不可以省略的,原因就是只有添加了符号",",才可以使得返回 值是 Line2D 对象。
<2>同理,通过调用"ax.plot(x,y,color="cornflowerblue",lw=3)"语句,获得的返回值"line"的 后面也需要添加符号","。
<3> 函数 init() 和 animate()分别作为参 数值传入 类 FuncAnimation 的构造函 数中。类FuncAnimation 的构造函数主要接收的参数有 Figure 对象、函数 func、帧数 frames、帧与帧之间的 间隔时间 interval。
<4>调用实例方法save(),将绘制的每帧动画画面(图形)保存成图像文件,然后将全部图像 文件转存成视频文件,也就是动画 mymovie.mp4,这个动画的文件格式是 MPEG-4 Movie。如果计 算机安装的是 Windows 操作系统,则可以使用系统自带的 Windows Media Player 软件打开,当然也 可以使用其他视频播放软件打开。动画保存在生成动画的执行脚本所在的路径下。
<5>调用模块 pyplot 中的函数 show(),生成自动播放动画内容的画布窗口。在图 7-1 中,展示 了从动画内容中选取的 4 帧动画画面。
二,调用模块 pyplot 的 API 绘制动画
1.代码示例
python
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.patches import Circle
from warnings import filterwarnings
# ignore warning
filterwarnings("ignore", ".*GUI is implemented.*")
# set several variables
word = "kaleidoscope"
row = int(len(word) / 4)
col = int(len(word) / 4)
num = int(len(word) / 4)
data = np.random.random((row, col, num))
colorMap = ["spring", "summer", "autumn", "winter"]
subplot_row = int(len(word) / 6)
subplot_col = int(len(word) / 6)
font = dict(family="monospace", weight="bold", style="italic", fontsize=10)
subplot_kw = dict(aspect="equal", frame_on=False, xticks=[], yticks=[])
# create subplots
fig, ax = plt.subplots(subplot_row, subplot_col, subplot_kw=subplot_kw)
# generate a subplot
def rowcolgenerator(r, c, season):
index = colorMap.index(season)
t = index * num
subtitle = "No.{} '{}' Theme of the {}"
for j in range(len(data)):
ax[r, c].cla()
collection = ax[r, c].pcolor(data[j, :], cmap=colorMap[index])
patch = Circle((1.5, 1.5), radius=1.5, transform=ax[r, c].transData)
collection.set_clip_path(patch)
element = colorMap[index].capitalize()
ax[r, c].set_title(subtitle.format((j + 1), word[t:t + 3], element),
**font)
ax[r, c].set_axis_off()
plt.pause(1.0)
# create animation
def animation():
i = 0
for r in range(subplot_row):
for c in range(subplot_col):
rowcolgenerator(r, c, colorMap[i])
i += 1
title = "Life Kaleidoscope Consists of Four Seasons"
plt.suptitle(title, family="serif", weight="black", fontsize=20)
plt.subplots_adjust(wspace=0.05, hspace=0.2)
if __name__ == "__main__":
animation()
2.代码讲解
(1)导入模块 pyplot、patches 和 warnings,其中,模块 patches 主要用于导入类 Circle,模块 warnings 主要用于导入函数 filterwarnings()。导入 NumPy 包用于生成类 ndarray 的数据对象。 注意: 函数 filterwarnings(action,message)主要用来设置对于警告信息而言脚本所采用的运行模式,其中, 参数 action 用来设置脚本运行模式,参数 message 用来收集必须与正则表达式相匹配的警告信息。
(2)通过调用"np.random.random((row,col,num))"语句,生成在半开区间(0.0,1.0]内的随机浮点数的数组 array,数据对象 ndarray 的形状是 row 行 col 列,而且数组 array 中的每个元素都包含 num 个浮点数。
(3)通过调用"colorMap = ["spring","summer","autumn","winter"]"语句,将颜色映射表的名称存储在列表 colorMap 中。
(4)通过调用"subplot_kw = dict(aspect="equal",frame_on=False,xticks=[],yticks=[])"语句,用字 典数据结构设置子区的坐标轴的展示形式,参数 aspect 的取值将 x 轴的刻度线之间的单位距离和 y轴的刻度线之间的单位距离设置成长度相同,参数 frame_on 的取值将轴脊隐藏,参数 xticks 和 yticks 的取值分别将 x 轴和 y 轴的刻度线去掉,相应地,也将坐标轴上的刻度标签去掉。
(5)函数 rowcolgenerator()的功能主要是在每个子区上绘制图形。具体而言,通过调用 "ax[r,c].cla()"语句,清除当前子区里的坐标轴 ax[r,c]上的图形。然后在坐标轴 ax[r,c]上,调用类 Axes 的实例方法重新绘制图形,也就是通过调用"ax[r,c].pcolor(data[j,:],cmap=colorMap[index])"语句, 绘制模拟颜色图,参数 cmap 用来设置模拟颜色图所使用的颜色映射表的名称。通过调用 "Circle((1.5,1.5),radius=1.5,transform=ax[r,c].transData)"语句,绘制一个半径为 1.5、圆心(1.5,1.5)位 置处的圆形补片,参数 transform 的取值表示使用 ax[r,c]的坐标系统,也就是使用类 Axes 的坐标系 统,例如,(0,0)表示坐标轴的左下角,(1,1)表示坐标轴的右上角。调用类 Collection 的实例方法 set_clip_path(),将圆形补片 patch 作为剪切模板或裁剪路径,裁剪出一幅圆形样式的模拟颜色图。 变量 element 存储的是首字母大写的颜色映射表的名称。调用类 Axes 的实例方法 set_title()设置子区 的文本标题。调用类 Axes 的实例方法 set_axis_off()关闭 x 和 y 坐标轴,也就是说,将两个维度的坐 标轴隐藏。最后,调用模块 pyplot 中的函数 pause(),设置在执行下一句代码之前的延迟时间,这个 函数一般可以用来实现简单的动画效果。
(6)函数 animation()的功能主要是通过 for 循环语句,分别在每个子区上绘制圆形模拟颜色图。 其中,调用模块 pyplot 中的函数 suptitle()在画布上添加文本标题,调用模块 pyplot 中的函数 subplots_adjust()分别设置子区之间的宽度和高度。
(7) 通过if语句,如果执行脚本,那么条件表达式"name == "main""的返回值是"True", 进而调用函数 animation(),从而完成绘制动画的任务。