MPL-03:使用matplotlib繪制動畫

本主題主要介紹:
??1. matplotlib中動畫相關(guān)API說明;
??2. matplotlib動畫繪制編程模式;
??3. 動畫的保存方式赠堵;

一.摘要

  • matplotlib動畫模塊主要包含兩個應(yīng)用

    1. 動畫的實現(xiàn)
    2. 動畫的保存
      • mp4
      • gif
      • html
  • 動畫的實現(xiàn)残家,主要由如下三個類實現(xiàn):

    • Animation 創(chuàng)建動畫。

    • FuncAnimation 動過反復(fù)調(diào)用函數(shù)來實現(xiàn)一個動畫暂殖。

    • ArtistAnimation 使用一組Artist對象來實現(xiàn)動畫。

    • TimedAnimation 基于時間的動畫實現(xiàn)当纱。

  • 動畫的保存呛每,主要由如下三個類實現(xiàn):

    • FFMpegFileWriter:基于文件的ffmpeg寫入器. 'mp4'
    • ImageMagickFileWriter:基于文件的animated gif寫入器. 'gif'
    • AVConvFileWriter:基于文件的avconv寫入器. 'avi'
  • 說明:

    • 還有緩沖寫入器:PillowWriter

    • 管道寫入器:FFMpegWriter,ImageMagickWriter坡氯,AVConvWriter晨横。

    • 上面三中寫入器都是MovieWriter的子類,使用管道方式箫柳。

      • 還有一個依賴pillow圖像庫的寫入器:'PillowWriter'手形,使用哪一個寫入器看各自機器的環(huán)境。

二.FuncAnimation 動畫實現(xiàn)

2.1. FuncAnimation類說明

    class matplotlib.animation.FuncAnimation(
        fig,     # 動畫所在的圖
        func,    # 動畫函數(shù)悯恍,第一個參數(shù)是下一幀的值叁幢, 其他參數(shù)由fargs傳遞。
        frames=None,      # 動畫幀數(shù)
        init_func=None,    # 初始化函數(shù)坪稽,用于清空圖形曼玩,如果不設(shè)置,則使用func中第一幀圖像窒百。
        fargs=None,         # 一個字典類型的數(shù)據(jù)黍判,會作為func函數(shù)的參數(shù)。
        save_count=None,     # 緩沖的動畫幀數(shù)量
        *, 
        cache_frame_data=True, 
        **kwargs)
           |- interval:間隔時間篙梢; 單位milliseconds毫秒1/1000
           |- repeat:是否重復(fù)播放顷帖;
           |- 其他參數(shù)參考文檔。
        
  • 動畫函數(shù)
    def func(frame, *fargs) -> iterable_of_artists
  • 該類有一個方法用來生成動畫的保存文件:
    • save(self, filename, writer=None, fps=None, dpi=None, codec=None, bitrate=None, extra_args=None, metadata=None, extra_anim=None, savefig_kwargs=None)
      • filename:保存的文件名
      • writer:FFMpegFileWriter渤滞,ImageMagickFileWriter贬墩, AVConvFileWriter對象實例,或者表示這些對象的字符串('ffmpeg', 'imagemagick','avconv')
      • fps:每秒的幀數(shù)
      • dpi:每英寸的像素個數(shù)妄呕,與figsize結(jié)合一起就是輸出的高寬陶舞。
      • 其他參數(shù)過于專業(yè),使用默認(rèn)參數(shù)即可绪励。
      • 這個函數(shù)的詳細(xì)幫助肿孵,可以使用如下方式獲取唠粥。
# from matplotlib.animation import FuncAnimation
# help(FuncAnimation.save)

2.2. 動畫的實現(xiàn)模式

  • 動畫的實現(xiàn)模式
    1. 構(gòu)造Figure對象實例;
    2. 構(gòu)造Axes對象實例停做;
    3. 構(gòu)造動畫的基本圖形晤愧;
    4. 定義動畫幀的函數(shù);
    5. 構(gòu)造FuncAnimation對象實例蛉腌,該對象調(diào)用動畫幀的函數(shù)產(chǎn)生動畫官份。
    6. 保存動畫為文件
# %matplotlib inline
import matplotlib.pyplot as plt
import matplotlib.animation as ani
import numpy as np

amplitude = 5   # sin曲線的振幅 
frames = 200    # 動畫總的幀數(shù)

#    1. 構(gòu)造Figure對象實例;
figure = plt.figure(figsize=(8, 4))
#    2. 構(gòu)造Axes對象實例烙丛;
ax = figure.add_axes([0.1, 0.1, 0.8, 0.8])
ax.set_xlim(0, 4*np.pi)     # 一定記得設(shè)置x與y軸的范圍贯吓,否則顯示一部分。
ax.set_ylim(-amplitude,  amplitude)

#    3. 構(gòu)造動畫的基本圖形蜀变;
[lines]= ax.plot([], [])   # 返回的是一個artist列表

x = np.linspace(0, 4*np.pi, frames)
y = np.sin(x) * amplitude

#    4. 定義動畫幀的函數(shù);
def ani_frame(frame):            # frame的最大值由FuncAnimation中的frames參數(shù)決定介评。
    lines.set_data(x[: frame], y[: frame])
    return [lines]
#    5. 構(gòu)造FuncAnimation對象實例库北,該對象調(diào)用動畫幀的函數(shù)產(chǎn)生動畫。
anim = ani.FuncAnimation(figure, ani_frame, frames=frames, interval=20,  blit=False, repeat=True)   
#    6. 保存動畫為文件
anim.save('sin1.gif', writer='pillow')

生成的動畫

2.3.設(shè)置初始化函數(shù)

  • 初始化函數(shù)就是第一幀的圖像们陆,如果不設(shè)置寒瓦,則默認(rèn)使用func指定的函數(shù)返回的第一幀作為動畫的第一幀。
# %matplotlib inline
import matplotlib.pyplot as plt
import matplotlib.animation as ani
import numpy as np

amplitude = 5   # sin曲線的振幅 
frames = 200    # 動畫總的幀數(shù)


figure = plt.figure(figsize=(8, 6))
ax = figure.add_axes([0.1, 0.1, 0.8, 0.8])
ax.set_xlim(0, 4*np.pi) 
ax.set_ylim(-amplitude,  amplitude)

[lines]= ax.plot([], [])   

x = np.linspace(0, 4*np.pi, frames)
y = np.sin(x) * amplitude

def ani_frame(frame):            
    lines.set_data(x[: frame], y[: frame])
    return [lines]
# -------------------------
# 初始化函數(shù)
def init():
    lines.set_data(x, y)
    return [lines]

anim = ani.FuncAnimation(figure, ani_frame,  init_func=init, frames=frames, interval=20,  blit=False, repeat=True)   
anim.save('sin2.gif', writer='pillow')
生成的動畫圖像

2.4. 需要注意的事項

  1. 如下兩個環(huán)境顯示不了動畫坪仇,需要顯示動畫杂腰,使用單獨的應(yīng)用啟動界面。
    • 在Jupyter顯示的圖形顯示不了動畫椅文;
    • Pycharm的內(nèi)置plot顯示環(huán)境中顯示不了動畫喂很;需要單獨的窗體顯示。


      獨立窗體運行的動畫
  1. 使用blit=True參數(shù)的問題:
    • 使用blit=True主要優(yōu)化繪制過程皆刺,通過緩沖翻轉(zhuǎn)的方式實現(xiàn)少辣。
    • 但是在Mac OS系統(tǒng)中,如果使用blit=True會出現(xiàn)錯誤羡蛾,解決辦法兩個:
      • 使用blit=False漓帅,不使用緩沖優(yōu)化的方式;
      • 在import matplotlib.pyplot之間使用如下語句:

    import matplotlib
    matplotlib.use('TKAgg')

2.5. 動畫保存

2.5.1. 獲取動畫保存的writers

import matplotlib
import matplotlib.animation as ani
ani.writers.list()    # ffmpeg需要安裝ffmpeg軟件:mac安裝指令: brew install ffmpeg
['pillow', 'ffmpeg', 'ffmpeg_file', 'html']

2.5.2. 獲取動畫保存的編碼

import matplotlib
import matplotlib.pyplot as plt

matplotlib.rcParams['animation.codec']

plt.rcParams['animation.codec']
'h264'

2.5.3. 使用writer實例保存

# coding=utf-8
import matplotlib.pyplot as plt
import matplotlib.animation as ani
import numpy as np
from matplotlib.animation import PillowWriter

amplitude = 5   # sin曲線的振幅
frames = 200    # 動畫總的幀數(shù)


figure = plt.figure(figsize=(8, 6))
ax = figure.add_axes([0.1, 0.1, 0.8, 0.8])
ax.set_xlim(0, 4*np.pi)
ax.set_ylim(-amplitude,  amplitude)

[lines]= ax.plot([], [])

x = np.linspace(0, 4*np.pi, frames)
y = np.sin(x) * amplitude


def ani_frame(frame):
    lines.set_data(x[: frame], y[: frame])
    return [lines]


def init():
    lines.set_data(x, y)
    return [lines]


anim = ani.FuncAnimation(figure, ani_frame,  init_func=init, frames=frames, interval=20,  blit=False, repeat=True)
# 使用PillowWriter對象實例-------------------
writer = PillowWriter(codec='h264')
anim.save('sin3.gif', writer=writer)
# --------------------------------------


生成的動畫圖像

html保存

# coding=utf-8
import matplotlib.pyplot as plt
import matplotlib.animation as ani
import numpy as np
from matplotlib.animation import PillowWriter

amplitude = 5   # sin曲線的振幅
frames = 200    # 動畫總的幀數(shù)


figure = plt.figure(figsize=(8, 4))
ax = figure.add_axes([0.1, 0.1, 0.8, 0.8])
ax.set_xlim(0, 4*np.pi)
ax.set_ylim(-amplitude,  amplitude)

[lines]= ax.plot([], [])

x = np.linspace(0, 4*np.pi, frames)
y = np.sin(x) * amplitude


def ani_frame(frame):
    lines.set_data(x[: frame], y[: frame])
    return [lines]


def init():
    lines.set_data(x, y)
    return [lines]


anim = ani.FuncAnimation(figure, ani_frame,  init_func=init, frames=frames, interval=20,  blit=False, repeat=True)
# --------------------------------------
anim.save('sin.html', writer='html')
# --------------------------------------
# plt.show()

保存為html文件的效果

2.5.4. 保存為mp4

# coding=utf-8
import matplotlib.pyplot as plt
import matplotlib.animation as ani
import numpy as np
from matplotlib.animation import PillowWriter

amplitude = 5   # sin曲線的振幅
frames = 200    # 動畫總的幀數(shù)


figure = plt.figure(figsize=(8, 4))
ax = figure.add_axes([0.1, 0.1, 0.8, 0.8])
ax.set_xlim(0, 4*np.pi)
ax.set_ylim(-amplitude,  amplitude)

[lines]= ax.plot([], [])

x = np.linspace(0, 4*np.pi, frames)
y = np.sin(x) * amplitude


def ani_frame(frame):
    lines.set_data(x[: frame], y[: frame])
    return [lines]


def init():
    lines.set_data(x, y)
    return [lines]


anim = ani.FuncAnimation(figure, ani_frame,  init_func=init, frames=frames, interval=20,  blit=False, repeat=True)
# --------------------------------------
anim.save('sin.mp4', writer='ffmpeg')
# ImageMagickFileWriter
# anim.save('sin.gif', writer='imagemagick')

# --------------------------------------
# plt.show()


保存為mp4視頻的播放效果

三. 官網(wǎng)提供的例子

  • 官方的幫助文檔提供了幾個比較經(jīng)典的例子痴怨,可以參考來實現(xiàn)自己想要的效果忙干。


    官方的幫助文檔提供的例子清單
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation

# Fixing random state for reproducibility
np.random.seed(19680801)


# Create new Figure and an Axes which fills it.
fig = plt.figure(figsize=(7, 7))
ax = fig.add_axes([0, 0, 1, 1], frameon=False)
ax.set_xlim(0, 1), ax.set_xticks([])
ax.set_ylim(0, 1), ax.set_yticks([])

# Create rain data
n_drops = 50
rain_drops = np.zeros(n_drops, dtype=[('position', float, 2),
                                      ('size',     float, 1),
                                      ('growth',   float, 1),
                                      ('color',    float, 4)])

# Initialize the raindrops in random positions and with
# random growth rates.
rain_drops['position'] = np.random.uniform(0, 1, (n_drops, 2))
rain_drops['growth'] = np.random.uniform(50, 200, n_drops)

# Construct the scatter which we will update during animation
# as the raindrops develop.
scat = ax.scatter(rain_drops['position'][:, 0], rain_drops['position'][:, 1],
                  s=rain_drops['size'], lw=0.5, edgecolors=rain_drops['color'],
                  facecolors='none')


def update(frame_number):
    # Get an index which we can use to re-spawn the oldest raindrop.
    current_index = frame_number % n_drops

    # Make all colors more transparent as time progresses.
    rain_drops['color'][:, 3] -= 1.0/len(rain_drops)
    rain_drops['color'][:, 3] = np.clip(rain_drops['color'][:, 3], 0, 1)

    # Make all circles bigger.
    rain_drops['size'] += rain_drops['growth']

    # Pick a new position for oldest rain drop, resetting its size,
    # color and growth factor.
    rain_drops['position'][current_index] = np.random.uniform(0, 1, 2)
    rain_drops['size'][current_index] = 5
    rain_drops['color'][current_index] = (0, 0, 0, 1)
    rain_drops['growth'][current_index] = np.random.uniform(50, 200)

    # Update the scatter collection, with the new colors, sizes and positions.
    scat.set_edgecolors(rain_drops['color'])
    scat.set_sizes(rain_drops['size'])
    scat.set_offsets(rain_drops['position'])


# Construct the animation, using the update function as the animation director.
animation = FuncAnimation(fig, update, interval=10)

animation.save('rain.gif', writer='pillow')
官方的例子效果
  • 還提供一個基于已經(jīng)準(zhǔn)備好的plot的動畫類ArtistAnimation
    • 該類是使用先繪制好的圖形來產(chǎn)生動畫。FuncAnimation是使用函數(shù)返回的圖形來產(chǎn)生動畫浪藻。兩者的最終目的都一樣捐迫,個人覺得FuncAnimation復(fù)合開發(fā)者的習(xí)慣。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末爱葵,一起剝皮案震驚了整個濱河市弓乙,隨后出現(xiàn)的幾起案子末融,更是在濱河造成了極大的恐慌,老刑警劉巖暇韧,帶你破解...
    沈念sama閱讀 217,907評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件勾习,死亡現(xiàn)場離奇詭異,居然都是意外死亡懈玻,警方通過查閱死者的電腦和手機巧婶,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,987評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來涂乌,“玉大人艺栈,你說我怎么就攤上這事⊥搴校” “怎么了湿右?”我有些...
    開封第一講書人閱讀 164,298評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長罚勾。 經(jīng)常有香客問我毅人,道長,這世上最難降的妖魔是什么尖殃? 我笑而不...
    開封第一講書人閱讀 58,586評論 1 293
  • 正文 為了忘掉前任丈莺,我火速辦了婚禮,結(jié)果婚禮上送丰,老公的妹妹穿的比我還像新娘缔俄。我一直安慰自己,他們只是感情好器躏,可當(dāng)我...
    茶點故事閱讀 67,633評論 6 392
  • 文/花漫 我一把揭開白布俐载。 她就那樣靜靜地躺著,像睡著了一般登失。 火紅的嫁衣襯著肌膚如雪瞎疼。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,488評論 1 302
  • 那天壁畸,我揣著相機與錄音贼急,去河邊找鬼。 笑死捏萍,一個胖子當(dāng)著我的面吹牛太抓,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播令杈,決...
    沈念sama閱讀 40,275評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼走敌,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了逗噩?” 一聲冷哼從身側(cè)響起掉丽,我...
    開封第一講書人閱讀 39,176評論 0 276
  • 序言:老撾萬榮一對情侶失蹤跌榔,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后捶障,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體僧须,經(jīng)...
    沈念sama閱讀 45,619評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,819評論 3 336
  • 正文 我和宋清朗相戀三年项炼,在試婚紗的時候發(fā)現(xiàn)自己被綠了担平。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,932評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡锭部,死狀恐怖暂论,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情拌禾,我是刑警寧澤取胎,帶...
    沈念sama閱讀 35,655評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站湃窍,受9級特大地震影響闻蛀,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜坝咐,卻給世界環(huán)境...
    茶點故事閱讀 41,265評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望析恢。 院中可真熱鬧墨坚,春花似錦、人聲如沸映挂。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,871評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽柑船。三九已至帽撑,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間鞍时,已是汗流浹背亏拉。 一陣腳步聲響...
    開封第一講書人閱讀 32,994評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留逆巍,地道東北人及塘。 一個月前我還...
    沈念sama閱讀 48,095評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像锐极,于是被迫代替她去往敵國和親笙僚。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,884評論 2 354

推薦閱讀更多精彩內(nèi)容