[Matplotlib] アニメーションの作成

[Matplotlib] アニメーションの作成

アニメーションの作成

 数値シミュレーションなどを行なう際に、解析結果をアニメーションとして表現すると現象を把握しやすくなることもあります。matplotlib.animationパッケージ には、データを動的に可視化するための ArtistAnimation()FuncAnimation() が用意されています。

matplotlib.animation.ArtistAnimation()

 ArtistAnimation()関数でアニメーションを作成する場合は、予めすべてのプロットデータを渡すことになります。例として右方向に進む正弦波のアニメーションを表示させてみましょう。Jupyter Notebook でアニメーションを描画させるためには、%matplotlib nbagg というマジックコマンドが必要です。

# リストA-1
# ArtistAnimation() サンプルコード

%matplotlib nbagg
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import animation

# FigureとAxes
fig = plt.figure(figsize = (5, 5))
ax = fig.add_subplot(111)
ax.grid()
ax.set_xlim(0, 2 * np.pi)
ax.set_ylim(-1.5, 1.5)
ax.set_xlabel("x", fontsize = 15)
ax.set_ylabel("y", fontsize = 15)

ims = []
x = np.linspace(0, 2*np.pi)

# サブプロットのリストを用意
for t in range(100):
    y = np.sin(x - t)
    artist = ax.plot(x, y, color = "b")
    ims.append(artist)

# アニメーションを作成
ani = animation.ArtistAnimation(
      fig,  # Figureオブジェクト
      ims,  # サブプロット(Axes)のリスト
      interval = 200,  # サブプロットの更新頻度(ms)
      blit = True  # blitting による処理の高速化
      )

plt.show()

Python 左から右へ進行する正弦波のアニメーション
 リストA-1では for文を使って ims に Axesオブジェクトをまとめて 100個格納し、それを ArtistAnimation() に渡してアニメーションを表示しています。interval はサブプロットの更新間隔です。単位は ms (ミリ秒) なので、リストA-1では 200 × 0.001 = 0.2 秒間隔に設定していることになります。
 

matplotlib.animation.FuncAnimation()

 FuncAnimation() の第2引数には「グラフを描画する関数」を渡します。
 すなわち、FuncAnimation() は受け取った関数を逐次呼び出してサブプロット (Axes) を更新することでアニメーションを表示します。ArtisitAnimation() に比べて柔軟性で勝りますが、処理負担は大きくなります。

FuncAnimation() サンプルコード[1]

 二次関数 $y=ax^2$ の係数 $a$ を変化させるグラフを描いてみます。

# リストB-1
# FuncAnimation() サンプルコード[1]

fig, ax = plt.subplots(figsize = (5, 5))
ax.set_xlim(-4, 4)
ax.set_ylim(0, 10)
ax.set_xlabel("x", fontsize = 15)
ax.set_ylabel("y", fontsize = 15)
ax.grid()

line, = ax.plot([0], [0], 'b')

x = np.linspace(-5, 5, 129)

def update(a):
    y = a * x**2
    line.set_data(x, y)

ani = animation.FuncAnimation(
      fig,  # Figureオブジェクト
      update,  # グラフ描画関数
      frames = np.arange(0, 10, 0.1),  # フレームを設定
      interval = 100,  # 更新間隔(ms)
      repeat = True,  # 描画を繰り返す
      blit = True  # blitting による処理の高速化
      )

ani.save('ani_update.gif', writer='pillow')
plt.show()

Python 二次関数の係数変化アニメーション

 frames に渡した値は、グラフ描画関数の引数に渡されます。
 リストB-1では update() の t に順次

  t = 0, 0.1, 0.2, 0.3, ...... 9.8, 9.9

を渡して座標 y を計算します。このように逐次データを更新しながらサブプロットを連続表示することでアニメーションを表現しますが、その更新間隔を決めるのが interval という引数です。単位は ms (ミリ秒) なので、リストB-1では 100 × 0.001 = 0.1 秒毎にサブプロットを更新していることになります。

FuncAnimation() サンプルコード[2]

 媒介変数方程式
\[x(t)=\cos t,\quad y(t)=\sin t\]
を使って円運動を表示するコードです。

# リストB-2
# FuncAnimation() サンプルコード[2]

# AxesとFigureを設定
fig, ax = plt.subplots(figsize = (5, 5))
ax.set_xlim(-1.5, 1.5)
ax.set_ylim(-1.5, 1.5)
ax.set_xlabel("x", fontsize = 15)
ax.set_ylabel("y", fontsize = 15)
ax.grid()

dot, = ax.plot([0], [0], 'bo')

def dot_circle(t):
    xt = np.cos(t)
    yt = np.sin(t)
    dot.set_data(xt, yt)
    return dot,

ani = animation.FuncAnimation(
      fig,  # Figureオブジェクト
      dot_circle,  # グラフ描画関数
      frames = np.arange(0, 30, 0.1),  # フレームを設定
      interval = 100,  # 更新間隔(ms)
      repeat = True,  # 描画を繰り返す
      blit = True  # blitting による処理の高速化
      )

plt.show()

Python 円運動アニメーション