【转】如何用 Matplotlib 画 GIF 动图

先占个位,以后解释原理

如何用 Matplotlib 画 GIF 动图

今天分享的这篇译文中介绍了 matplotlib 绘图库的一个 使用示例,即如何制作 GIF 动图。本文原作者为 Eli Bendersky,译者为 唐晓霆 Jason ,由编程派 EarlGrey 校对。

译者简介:唐晓霆,在香港的成都人,城市大学研究助理,会写python,兴趣是深度学习。

这篇短文介绍如何用 Python 里的 matplotlib 画出 GIF 动图。下面的代码我在一台安装了 ImagMagickUbuntu 机器上运行过。 若想要用 matplotlibsave 方法渲染 GIF 动图的话,就必须安装 ImageMagick

下面给一个动画样本:

有几点需要注意:

  1. 图里的散点部分是不变的;变的是直线
  2. 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
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,911评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,014评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 142,129评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,283评论 1 264
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,159评论 4 357
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,161评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,565评论 3 382
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,251评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,531评论 1 292
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,619评论 2 310
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,383评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,255评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,624评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,916评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,199评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,553评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,756评论 2 335