uitspitss blog

プログラミングと音楽とエッセイ ※記載内容は個人の見解であり、所属する組織とは一切関係がありません。

python + matplotlib でグラフのアニメーション

前回に引き続き、備忘録の第二弾です!

去年やっていたプロジェクトの最初の頃に、 作ったアルゴリズムの動作確認のために使って、 お世話になりました!

python + matplotlib においては、 グラフのアニメーションもお手の物なんだけど、 いろいろと注意することがあったりする

環境

matplotlib のインストール

pip install matplotlib

プログラム

#!python
#-*-coding:utf-8-*-
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as anim

def main():
    fig = plt.figure()
    ax = fig.add_subplot(111)

    frames = []
    for dx in np.arange(1, 10, 0.1):
        x = np.linspace(0, 5, 100)
        y = np.sin(x + dx)
        tmp_frame, = ax.plot(x, y, "b-")
        frames.append([tmp_frame])

    ax.axis([0, 5, -1.1, 1.1])
    ani = anim.ArtistAnimation(fig, frames, interval=1, repeat=True, repeat_delay=1000)

    plt.show(block=False)
    input("Enter to close")
    plt.close()

    # ani.save("test.mp4", writer="ffmpeg", fps=30, bitrate=1000)

    print("end")

if __name__ == '__main__':
    main()

コード中のコメントアウトしている箇所で、動画を保存できる。
今回のコードでできた動画はこんな感じ↓
f:id:uitspitss:20160417210819g:plain

注意すべきところなど

matplotlibのアニメーション

matplotlibでは、FuncAnimationArtistAnimationという、 2通りの関数が用意されている。
FuncAnimationは、動的にグラフを書き換えていくという感じであるが、 アニメーションのフレームが変わったあとに、 前のフレームで書かれたものが残っているため、 それを消してから、次のフレームを書かなければいけない。
と、慣れればそれほどではないのかもしれないが、 とっつきにくい感じがあった。
一方、ArtistAnimationはあらかじめフレームのリストを生成して、 そのリストにフレームごとの描画結果をappendしていく感じ。
私は、こちらの方が好みだったので、今回はこちらの関数を使っている。
FuncAnimationの使い所としては、 今回のプログラムのax.axis([0, 5, -1.1, 1.1])のところに関連して、 今回はこのコードによって、すべてのフレームの描画される範囲を一括で指定しているが、 この範囲がフレームによって変わる場合はFuncAnimationのほうがよいのかもしれない。

plotの返り値について

また、よくつまづくポイントとして、 今回のコード中のtmp_frame, = ax.plot(x, y, "b-")のところ。 意味としては、あるフレームの描画を変数に格納しているだけだが、 ax.plot() の返り値は要素数1個のリストで返ってくるので、 それをunpackしてから、フレームリストに追加しなければいけない。

ちょっとしたTips

最後に、Tipsを。
私は Emacs + quickrun.el という組み合わせで開発をしているが、 plt.show() をしてから、開かれたウィンドウを閉じるのが手間に感じる。
そこで、この手間を多少解消してくれるTipsが stack overflow にあったので紹介する。
stack overflow
今回のコードでは、

plt.show(block=False)
input("Enter to close")
plt.close()

の所。
ただし、アニメーションのときは、フレームリスト一周分が回らないと、
input()の待機状態に入らなかったので、 最初の段階ではフレーム数を少なめにしてグラフの体裁を調整、 最後の段階でフレーム数を増やす、というやり方がよさそう。
また、書いていて思ったが、Jupyter Notebook とかなら、 アニメーションもあのコンソールの中で表示してくれそう。
後日、試してみます♪