本主題主要介紹:
??1. matplotlib中動畫相關(guān)API說明;
??2. matplotlib動畫繪制編程模式;
??3. 動畫的保存方式赠堵;
一.摘要
-
matplotlib動畫模塊主要包含兩個應(yīng)用
- 動畫的實現(xiàn)
- 動畫的保存
- 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)模式
- 構(gòu)造Figure對象實例;
- 構(gòu)造Axes對象實例停做;
- 構(gòu)造動畫的基本圖形晤愧;
- 定義動畫幀的函數(shù);
- 構(gòu)造FuncAnimation對象實例蛉腌,該對象調(diào)用動畫幀的函數(shù)產(chǎn)生動畫官份。
- 保存動畫為文件
# %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. 需要注意的事項
- 如下兩個環(huán)境顯示不了動畫坪仇,需要顯示動畫杂腰,使用單獨的應(yīng)用啟動界面。
- 在Jupyter顯示的圖形顯示不了動畫椅文;
-
Pycharm的內(nèi)置plot顯示環(huán)境中顯示不了動畫喂很;需要單獨的窗體顯示。
獨立窗體運行的動畫
- 使用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í)慣。
- 該類是使用先繪制好的圖形來產(chǎn)生動畫。