Matplotlib 1.1+ 內建 animation 模組,透過 FuncAnimation 實現幀級動畫渲染。核心機制:周期性呼叫更新函式、修改繪圖物件資料、重繪畫布。本文系統解析四種資料來源模式、blit 技術、儲存輸出、效能調優與五個完整實戰範例。
ani = animation.FuncAnimation(
fig, # Figure 物件
func, # 更新函式 (每幀呼叫)
frames, # 幀資料來源 (int/iterable/generator)
init_func, # 初始化函式 (可選,blit 需要)
interval, # 幀間隔 (毫秒)
blit, # 是否只重繪變化部分 (關鍵優化)
repeat, # 是否循環
save_count # 儲存時幀數
)
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
fig, ax = plt.subplots()
line, = ax.plot(np.random.rand(10))
ax.set_ylim(0, 1)
def data_gen():
"""無限生成器:每次 yield 新資料"""
while True:
yield np.random.rand(10)
def update(data):
line.set_ydata(data)
return line,
ani = animation.FuncAnimation(fig, update, data_gen, interval=2000, blit=True)
plt.show()
特點:update 參數直接接收 yield 的值,非幀號。適用即時串流、感測器資料、模擬系統。
fig, ax = plt.subplots()
line, = ax.plot([1, 0.18, 0.63, 0.29, 0.03, 0.24, 0.86, 0.07, 0.58, 0])
metric = [
[0.03, 0.86, 0.65, 0.34, 0.34, 0.02, 0.22, 0.74, 0.66, 0.65],
[0.43, 0.18, 0.63, 0.29, 0.03, 0.24, 0.86, 0.07, 0.58, 0.55],
[0.66, 0.75, 0.01, 0.94, 0.72, 0.77, 0.20, 0.66, 0.81, 0.52]
]
def update(data):
line.set_ydata(data)
return line,
# frames 直接傳列表,每幀取一個元素
ani = animation.FuncAnimation(fig, update, metric, interval=2000, blit=True)
plt.show()
特點:frames 為列表時,每幀自動取一個元素傳給 update。適用預計算軌跡、關鍵幀動畫。
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
fig, ax = plt.subplots()
ax.set_xlim(0, 2)
ax.set_ylim(-2, 2)
line, = ax.plot([], [], lw=2)
def init():
line.set_data([], [])
return line,
def animate(frame_num):
"""frame_num 從 0 遞增"""
x = np.linspace(0, 2, 1000)
y = np.sin(2 * np.pi * (x - 0.01 * frame_num))
line.set_data(x, y)
return line,
# frames=200 表示 0..199
ani = animation.FuncAnimation(fig, animate, init_func=init, frames=200, interval=20, blit=True)
plt.show()
特點:frames 為整數時,update 參數為幀號 (0,1,2...)。適用數學函數、物理模擬、參數化動畫。
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
def data_gen():
t = 0
cnt = 0
while cnt < 1000:
cnt += 1
t += 0.05
yield t, np.sin(2*np.pi*t) * np.exp(-t/10.)
fig, ax = plt.subplots()
line, = ax.plot([], [], lw=2)
ax.set_ylim(-1.1, 1.1)
ax.set_xlim(0, 5)
ax.grid()
xdata, ydata = [], []
def run(data):
t, y = data
xdata.append(t)
ydata.append(y)
# 動態擴展 X 軸
xmin, xmax = ax.get_xlim()
if t >= xmax:
ax.set_xlim(xmin, 2*xmax)
ax.figure.canvas.draw()
line.set_data(xdata, ydata)
return line,
ani = animation.FuncAnimation(fig, run, data_gen, blit=True, interval=10, repeat=False)
plt.show()
特點:生成器維持狀態 (t, cnt),run 累積資料並動態調整座標軸。適用長時間監控、示波器、軌跡繪製。
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
fig, ax = plt.subplots()
data = np.random.rand(2, 15) # 2 行 15 列
line, = ax.plot([], [], 'r-')
ax.set_xlim(0, 1)
ax.set_ylim(0, 1)
def update_line(frame_num, data, line):
"""frame_num 從 0 遞增,data 為 fargs 傳入"""
line.set_data(data[0, :frame_num], data[1, :frame_num])
return line,
# frames=25:幀號 0..24 (資料有 15 點,超過後重複)
ani = animation.FuncAnimation(fig, update_line, 25, fargs=(data, line), interval=50, blit=True)
plt.show()
特點:fargs 傳遞固定資料,update 簽名為 (frame_num, *fargs)。適用固定資料集的逐步顯示。
| 模式 | blit=False | blit=True |
|---|---|---|
| 重繪範圍 | 整個 Figure | 僅回傳藝術家列表的變化區域 |
| 效能 | 慢 (全畫布重繪) | 快 (部分更新) |
| init_func | 可選 | 必要 (建立背景快取) |
| update 回傳 | 任意 | 必須回傳藝術家序列 (line,) |
# blit=True 必要條件
def init():
line.set_data([], [])
return line, # 必須回傳序列
def animate(i):
line.set_data(x, y)
return line, # 必須回傳序列
ani = FuncAnimation(fig, animate, init_func=init, blit=True, ...)
# 儲存為 MP4 (需 ffmpeg)
ani.save('animation.mp4', writer='ffmpeg', fps=30,
extra_args=['-vcodec', 'libx264', '-pix_fmt', 'yuv420p'])
# 儲存為 GIF (需 imagemagick 或 pillow)
ani.save('animation.gif', writer='pillow', fps=10)
# 儲存為 HTML5 (內嵌 JS 播放器)
html = ani.to_jshtml()
with open('animation.html', 'w') as f:
f.write(html)
init_funcmarkevery、下採樣、set_data 替換 plotLine2D、Text、Collectionxlim/ylim、關閉不必要 grid/legendmultiprocessing 分割
fig, axes = plt.subplots(2, 1, sharex=True)
lines = [ax.plot([], [])[0] for ax in axes]
def animate(frame):
for i, (ax, line) in enumerate(zip(axes, lines)):
x = np.linspace(0, 10, 100)
y = np.sin(x + frame * 0.1 * (i+1))
line.set_data(x, y)
ax.relim()
ax.autoscale_view()
return lines
ani = FuncAnimation(fig, animate, frames=200, interval=50, blit=True)
| 問題 | 原因 | 解決 |
|---|---|---|
| 動畫不動/靜止 | 未呼叫 plt.show()、interval 太大、blit=True 但無 init_func | 檢查 show()、interval、init_func 回傳藝術家 |
| 閃爍/殘影 | blit=False 全畫布重繪、背景未清除 | 啟用 blit=True、確保 init_func 正確 |
| 儲存失敗 | 缺少 ffmpeg/imagemagick/pillow | 安裝對應 writer、或用 to_jshtml() |
| 記憶體洩漏 | 長時間運行累積資料、未清理 | 限制資料長度、定期重置、使用生成器 |
| Jupyter 不顯示 | 需特殊輸出格式 | 用 %matplotlib notebook 或 ani.to_jshtml() |
Matplotlib 動畫核心:FuncAnimation(fig, func, frames, interval, blit=True)。五大資料模式:生成器 (串流)、列表 (預載)、幀號 (程式化)、生成器+狀態 (累積)、fargs (固定資料)。關鍵優化:blit=True + init_func + 回傳藝術家序列。掌握四種更新模式、blit 機制、儲存輸出、效能調優,能實現即時監控儀表板、科學模擬視覺化、教學動畫、資料逐步揭示等豐富應用。