如何用 Matplotlib 画 GIF 动图
- 原文来源:http://codingpy.com/article/drawing-gifs-with-matplotlib
- 转帖链接:编程派
- 类型:
python
今天分享的这篇译文中介绍了 matplotlib
绘图库的一个 使用示例,即如何制作 GIF
动图。本文原作者为 Eli Bendersky
,译者为 唐晓霆 Jason ,由编程派 EarlGrey 校对。
译者简介:唐晓霆,在香港的成都人,城市大学研究助理,会写python,兴趣是深度学习。
这篇短文介绍如何用 Python
里的 matplotlib
画出 GIF 动图。下面的代码我在一台安装了 ImagMagick
的 Ubuntu
机器上运行过。 若想要用 matplotlib
的 save
方法渲染 GIF
动图的话,就必须安装 ImageMagick
。
下面给一个动画样本:
有几点需要注意:
- 图里的散点部分是不变的;变的是直线
- X 轴的标题每一帧都在变化
下面上制作该图的代码:
import sys
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
fig, ax = plt.subplots()
fig.set_tight_layout(True)
# 询问图形在屏幕上的尺寸和DPI(每英寸点数)。
# 注意当我们把图形储存成一个文件时,我们需要再另外提供一个DPI值
print('fig size: {0} DPI, size in inches {1}'.format(
fig.get_dpi(), fig.get_size_inches()))
# 画出一个维持不变(不会被重画)的散点图和一开始的那条直线。
x = np.arange(0, 20, 0.1)
ax.scatter(x, x + np.random.normal(0, 3.0, len(x)))
line, = ax.plot(x, x - 5, 'r-', linewidth=2)
def update(i):
label = 'timestep {0}'.format(i)
print(label)
# 更新直线和x轴(用一个新的x轴的标签)。
# 用元组(Tuple)的形式返回在这一帧要被重新绘图的物体
line.set_ydata(x - 5 + i)
ax.set_xlabel(label)
return line, ax
if __name__ == '__main__':
# FuncAnimation 会在每一帧都调用“update” 函数。
# 在这里设置一个10帧的动画,每帧之间间隔200毫秒
anim = FuncAnimation(fig, update, frames=np.arange(0, 10), interval=200)
if len(sys.argv) > 1 and sys.argv[1] == 'save':
anim.save('line.gif', dpi=80, writer='imagemagick')
else:
# plt.show() 会一直循环播放动画
plt.show()
如果你想换一个更精美的主题,安装 seaborn 库之后添加一行:
import seaborn
然后你就会得到这个图:
提一句关于文件大小的警告:虽然我在这里分享的 GIF
只有 10 帧,而且图像也很简单,但是它们每一帧都占大约 160K 。就我理解而言,GIF
动图不使用跨帧压缩, 所以这使得长一点的 GIF
占的空间异常大。减少帧数到最最小并且让每一帧的图像小一点(通过在 matplotlib
里调整图形尺寸或者 DPI
),就可以多多少少帮助缓解一下这个问题。
EarlGrey:我自己测试生成的 line.gif 文件大概 86 KB 左右。
说明
我将源码测试过,但是在弹出框中的保存没有保存为 gif
。另外,按照代码中的说明,这样操作是可以保存为gif
的
python test.py save
但是之前作者说过,需要安装ImagMagick
,这个不是python
的包,是依赖于php
的一个工具,具体安装步骤可以见这里【windows下的ImageMagick安装详细过程】,感觉有点麻烦,其实也可以下载一个录屏的软件,然后制作为gif就好啦!
另外来自于知乎的 - 【如何用Python实现动态图? - 带萝卜的回答】
import matplotlib.pyplot as plt
import time
def insert_sort(lst):
lsts = []
for i in range(len(lst)):
temp = lst[i]
j = i-1
while j>=0 and lst[j]>temp:
lst[j+1] = lst[j]
j -= 1
lst[j+1] = temp
l = lst[:]
lsts.append(l)
return lsts
if __name__ == "__main__":
lst = [13,32,42,1,53,4,66,2,5,7,74,23]
lsts = insert_sort(lst)
plt.ion()#打开交互模式
fig = plt.figure()#新建绘图窗口
ax = plt.gca()#获取当前子图
bars = ax.bar(range(len(lst)),height=lst)#绘制条形图
for l in lsts:
print(l)
bars.remove()#删除条形图
bars = ax.bar(range(len(lst)),height=l)#绘制条形图
plt.pause(0.5)
while True:#防止图片关闭
plt.pause(1)
最上面的主要是用的FuncAnimation()
的功能,设定帧数,这样在运行代码的时候会一直循环。这里主要是利用了plt.pause()
这个方法来让plt绘图时候的暂停,因为图形中大部分的元素是没有发生改变的,所以看起来是连贯的,如果想要播放的间隔变短,可以调整间隔的时间长短,但是这种的不能一直循环,如果需要的话,可以在while True
的循环里面加上break
,然后把for
嵌套在while
里面,也实现了循环
import matplotlib.pyplot as plt
import time
def insert_sort(lst):
lsts = []
for i in range(len(lst)):
temp = lst[i]
j = i-1
while j>=0 and lst[j]>temp:
lst[j+1] = lst[j]
j -= 1
lst[j+1] = temp
l = lst[:]
lsts.append(l)
return lsts
if __name__ == "__main__":
lst = [13,32,42,1,53,4,66,2,5,7,74,23]
lsts = insert_sort(lst)
plt.ion()#打开交互模式
fig = plt.figure()#新建绘图窗口
ax = plt.gca()#获取当前子图
bars = ax.bar(range(len(lst)),height=lst)#绘制条形图
while True:
for l in lsts:
print(l)
bars.remove()#删除条形图
bars = ax.bar(range(len(lst)),height=l)#绘制条形图
plt.pause(0.5)
while True:#防止图片关闭
plt.pause(1)
break
网友评论