使用 Matplotlib 製作動畫#

基於其繪圖功能,Matplotlib 也提供了介面,可以使用 animation 模組來產生動畫。動畫是一連串的影格,其中每個影格對應到 Figure 上的圖表。本教學涵蓋了如何建立此類動畫的一般指南,以及可用的不同選項。更多資訊請參考 API 說明: animation

import matplotlib.pyplot as plt
import numpy as np

import matplotlib.animation as animation

動畫類別#

Matplotlib 中的動畫過程可以透過 2 種不同的方式來思考

  • FuncAnimation:產生第一影格的資料,然後修改每個影格的資料以建立動畫圖表。

  • ArtistAnimation:產生藝術家 (artist) 的清單(可迭代),這些藝術家將在動畫中的每個影格中繪製。

就速度和記憶體而言,FuncAnimation 效率更高,因為它會繪製藝術家一次,然後修改它。另一方面,ArtistAnimation 則很靈活,因為它允許在序列中動畫化任何可迭代的藝術家。

FuncAnimation#

FuncAnimation 類別允許我們透過傳遞一個迭代地修改圖表資料的函式來建立動畫。這是透過在各種 Artist 上使用 setter 方法來實現的(範例: Line2DPathCollection 等)。通常,FuncAnimation 物件會接收一個我們想要動畫的 Figure,以及一個修改在圖表上繪製資料的函式 func。它使用 frames 參數來判斷動畫的長度。interval 參數用於判斷繪製兩個影格之間的時間(以毫秒為單位)。使用 FuncAnimation 製作動畫通常需要這些步驟

  1. 像在靜態圖表中一樣繪製初始圖表。將所有已建立的藝術家(由繪圖函式傳回)儲存在變數中,以便您可以稍後在動畫函式中存取和修改它們。

  2. 建立一個動畫函式,該函式會更新給定影格的藝術家。通常,這會呼叫藝術家的 set_* 方法。

  3. 建立一個 FuncAnimation,傳遞 Figure 和動畫函式。

  4. 使用下列方法之一儲存或顯示動畫

下表顯示了一些繪圖方法、它們傳回的藝術家,以及一些常用的 set_* 方法,這些方法會更新基礎資料。雖然更新資料是動畫中最常見的操作,但您也可以更新其他方面,例如顏色或文字位置。

涵蓋所有類型藝術家 (artist) 的設定方法已超出本教學文件的範圍,但可以在它們各自的文件中找到。以下是如何使用 Axes.scatterAxes.plot 這些更新方法的範例。

fig, ax = plt.subplots()
t = np.linspace(0, 3, 40)
g = -9.81
v0 = 12
z = g * t**2 / 2 + v0 * t

v02 = 5
z2 = g * t**2 / 2 + v02 * t

scat = ax.scatter(t[0], z[0], c="b", s=5, label=f'v0 = {v0} m/s')
line2 = ax.plot(t[0], z2[0], label=f'v0 = {v02} m/s')[0]
ax.set(xlim=[0, 3], ylim=[-4, 10], xlabel='Time [s]', ylabel='Z [m]')
ax.legend()


def update(frame):
    # for each frame, update the data stored on each artist.
    x = t[:frame]
    y = z[:frame]
    # update the scatter plot:
    data = np.stack([x, y]).T
    scat.set_offsets(data)
    # update the line plot:
    line2.set_xdata(t[:frame])
    line2.set_ydata(z2[:frame])
    return (scat, line2)


ani = animation.FuncAnimation(fig=fig, func=update, frames=40, interval=30)
plt.show()

ArtistAnimation#

如果有多個不同藝術家 (artist) 儲存的資料,可以使用 ArtistAnimation 來產生動畫。這個藝術家 (artist) 列表會逐幀轉換成動畫。例如,當我們使用 Axes.barh 繪製長條圖時,它會為每個長條圖和誤差線建立許多藝術家 (artist)。要更新繪圖,需要個別從容器中更新每個長條圖並重新繪製。取而代之的是,可以使用 animation.ArtistAnimation 來單獨繪製每一幀,然後將它們拼接在一起形成動畫。長條圖競賽是這方面的一個簡單範例。

fig, ax = plt.subplots()
rng = np.random.default_rng(19680801)
data = np.array([20, 20, 20, 20])
x = np.array([1, 2, 3, 4])

artists = []
colors = ['tab:blue', 'tab:red', 'tab:green', 'tab:purple']
for i in range(20):
    data += rng.integers(low=0, high=10, size=data.shape)
    container = ax.barh(x, data, color=colors)
    artists.append(container)


ani = animation.ArtistAnimation(fig=fig, artists=artists, interval=400)
plt.show()

動畫寫入器#

動畫物件可以使用各種多媒體寫入器 (例如:Pillow、ffpmegimagemagick) 儲存到磁碟。並非所有寫入器都支援所有影片格式。主要有 4 種類型的寫入器

  • PillowWriter - 使用 Pillow 函式庫建立動畫。

  • HTMLWriter - 用於建立基於 JavaScript 的動畫。

  • 基於管道的寫入器 - FFMpegWriterImageMagickWriter 是基於管道的寫入器。這些寫入器將每一幀傳送到實用程式 (ffmpeg / imagemagick),然後將所有幀拼接在一起以建立動畫。

  • 基於檔案的寫入器 - FFMpegFileWriterImageMagickFileWriter 是基於檔案的寫入器範例。這些寫入器比它們的基於管道的替代方案慢,但對於偵錯更有用,因為它們會將每一幀儲存在檔案中,然後再將它們拼接成動畫。

儲存動畫#

寫入器

支援的格式

PillowWriter

.gif、.apng、.webp

HTMLWriter

.htm、.html、.png

所有 ffmpeg 支援的格式:ffmpeg -formats

所有 imagemagick 支援的格式:magick -list format

要使用任何寫入器儲存動畫,可以使用 animation.Animation.save 方法。它接受我們想要儲存動畫的檔案名稱寫入器,寫入器可以是字串或寫入器物件。它還接受一個 *fps* 引數。這個引數與 FuncAnimationArtistAnimation 使用的 *interval* 引數不同。 *fps* 決定了**已儲存**動畫使用的影格率,而 *interval* 決定了**已顯示**動畫使用的影格率。

以下是一些範例,展示如何使用不同的寫入器儲存動畫。

Pillow 寫入器

ani.save(filename="/tmp/pillow_example.gif", writer="pillow")
ani.save(filename="/tmp/pillow_example.apng", writer="pillow")

HTML 寫入器

ani.save(filename="/tmp/html_example.html", writer="html")
ani.save(filename="/tmp/html_example.htm", writer="html")
ani.save(filename="/tmp/html_example.png", writer="html")

FFMpegWriter

ani.save(filename="/tmp/ffmpeg_example.mkv", writer="ffmpeg")
ani.save(filename="/tmp/ffmpeg_example.mp4", writer="ffmpeg")
ani.save(filename="/tmp/ffmpeg_example.mjpeg", writer="ffmpeg")

Imagemagick 寫入器

ani.save(filename="/tmp/imagemagick_example.gif", writer="imagemagick")
ani.save(filename="/tmp/imagemagick_example.webp", writer="imagemagick")
ani.save(filename="apng:/tmp/imagemagick_example.apng",
         writer="imagemagick", extra_args=["-quality", "100"])

(apngextra_args 需要將檔案大小縮減約 10 倍)

請注意,需要單獨安裝 *ffmpeg* 和 *imagemagick*。獲取 *ffmpeg* 的跨平台方法是安裝 imageio_ffmpeg PyPI 套件,然後設定 rcParams["animation.ffmpeg_path"] = imageio_ffmpeg.get_ffmpeg_exe()

腳本總執行時間: (0 分鐘 6.699 秒)

由 Sphinx-Gallery 產生的圖庫