【Python】matplotlibでグラフのアニメーションを作る

matplotlibはPythonのグラフ描画ライブラリで、様々なグラフを描画することができます。そんなmatplotlibですが、なんとアニメーションで動くグラフを描画することもできるのです。

今回はサンプルデータを使ってグラフのアニメーション動画を作成する方法を紹介します。

出力結果とコード

今回はヒストグラムでアニメーションを作ってみます。以下で紹介するコードを実行すると、次のようなアニメーションが出力されます。

グラフ描画のコード全容

アニメーションを表示するためにJupyter Notebookを使用しました。

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from IPython.display import display, HTML

plt.style.use('seaborn')

def prepare_animation(bar_container):
     
    def animate(frame_number):
        data = np.random.randn(1000)
        n, _ = np.histogram(data, HIST_BINS)
         
        for count, rect in zip(n, bar_container):
            rect.set_height(count)
         
        return bar_container
     
    return animate
 
np.random.seed(19680804)
HIST_BINS = np.linspace(-4, 4, 100)
data = np.random.randn(1000)
  
fig, ax = plt.subplots()
_, _, bar_container = ax.hist(data, HIST_BINS, lw=1,ec="blue", fc="yellow", alpha=0.5)
ax.set_ylim(top=100)
ani = animation.FuncAnimation(fig, prepare_animation(bar_container), 50, blit=True)
HTML(ani.to_html5_video())

コード解説

ベースとなるデータの用意

まずはベースとなるデータをnumpyで作成します。データとヒストグラムのビンの範囲、スケールを指定しています。

np.random.seed(19680804)
HIST_BINS = np.linspace(-4, 4, 100)
data = np.random.randn(1000)

ax.hist()の第3引数は、各ビンの長方形を形成するためのオブジェクトです。今回の場合は100等分しているので、99個のオブジェクトが配列として保持されています。

ランダムにヒストグラムを生成

アニメーションとは動画、つまりフレームの連続体です。関数prepare_animation()は後述するアニメーション描画関数で用いるコールバック関数で、フレームごとにランダムなヒストグラムを生成します。

def prepare_animation(bar_container):
     
    def animate(frame_number):
        data = np.random.randn(1000)
        n, _ = np.histogram(data, HIST_BINS)
         
        for count, rect in zip(n, bar_container):
            rect.set_height(count)
         
        return bar_container
     
    return animate

今回の場合はprepare_animation()が複数回呼ばれることでランダムなヒストグラムのアニメーションを表現しています。

アニメーション描画

実際のアニメーション描画は、animation.FuncAnimation()で行います。

FuncAnimation(fig, func, frame, ** kwargs)

figにはmatplotlibの描画領域(plt.plotなど)を指定します。funcには各フレーム描画時に呼び出す関数を指定します。今回はprepare_animation()をフレーム描画ごとに呼び出しています。

frameはフレームの数を指定します。今回は50としたので、50フレームで1つのアニメーションになります。この引数はオプションです。

ani = animation.FuncAnimation(fig, prepare_animation(bar_container), 50, blit=True)

最後、アニメーションを描画するためにIPython.displayのHTMLを用いました。

animation.FuncAnimationのto_html5_video()関数を呼ぶと、アニメーションをHTML化してくれます。これを用いてHTMLとしてアニメーションを表示させます。

from IPython.display import display, HTML

HTML(ani.to_html5_video())

どんな場面で使える?

アニメーションの使い道ですが、当然静止画だけでは表現しきれない情報がある場合に用いるのがベストです。

例えば横軸が時系列でないグラフの年度ごとの推移などは1つのグラフでは表現しきれず、静止画であればグラフをいくつかに分けて表現する必要があります。その方法でも問題ありませんが、目線をずらして図を見比べる必要があります。また、グラフ数が多くなるほど比較が大変になります。

そういった場合にアニメーションを用いれば、推移がより把握しやすくなると思います。

まとめ

matplotlibでグラフをアニメーション表示する方法を紹介しました。matplotlibで動画も作れるとは、その対応範囲に驚きです。

ただ、動画を作成するにはそれなりのマシンスペックも求められるので、膨大なデータでアニメーションを作成する場合などには注意してください。

目的に合わせて適切な表現方法を探していきましょう^^