一口にアニメーションといっても時間毎に図の更新がみたいだけの場合とその様子を動画に保存したい場合とがある。
閲覧用のアニメーション
plt.pause(interval)
を用いることでノンブロッキングで現在の画像を更新していくことができる。
subplotsを用いた場合
ちょっと長くなるのが難点
import numpy as np import matplotlib.pyplot as plt # make data data = [[i, np.sin(i/50)] for i in range(100)] # prepare figure fig,ax = plt.subplots(1,1) ax.set_xlim(min([x[0] for x in data]),max([x[0] for x in data])) ax.set_ylim(min([x[1] for x in data]),max([x[1] for x in data])) xdata = [] ydata = [] line, = ax.plot(xdata,ydata) # iterate for dat in data: print(dat) xdata.append(dat[0]) ydata.append(dat[1]) line.set_data(xdata,ydata) plt.pause(0.1) # 10ms late
plt.figure()でやる方法
こっちのほうが楽。
import numpy as np import matplotlib.pyplot as plt # make data data = [[i, np.sin(i/50)] for i in range(100)] # prepare figure xdata = [] ydata = [] # iterate for dat in data: fig = plt.figure(1) xdata.append(dat[0]) ydata.append(dat[1]) plt.plot(xdata,ydata) plt.pause(0.1) # 10ms late plt.clf()
matplotlib.animationを使って図を保存する方法
matplotlibにはanimationという図を作成,保存するためのモジュールが存在する。
そのうち2つの手法が存在しイメージとしては以下のような感じである。
- ArtistAnimation:図をリスト形式で溜め込んで最後にまとめる。重い…?
- FuncAnimation:逐次的に図を作って追加していく。軽い…?
こちらはリアルタイムに描写というよりは,その後の保存に重点を置いている。一応plt.pause()とも連携できるはずだが,結構重いのでその辺は覚悟したほうが良いかも。
imagemagicのインストール
windows環境でやったのでLinuxの人は別の箇所を探して欲しいが,ffmpegとimagemagicをインストールすることでgifやmp4などの形式で動画を保存することができる。 実はimagemagicのインストール時にffmpegをインストールできるので実質imagemagicをインストールすれば良い。
以下のブログの手順に基づいてすすめていこう。 matplotlib のanimation を保存 - はしくれエンジニアもどきのメモ
1.imagemagicのインストール
こちらのダウンロードページに行き,Windows Binaryの一番上を選択してダウンロードすれば良い。 ダウンロード後はいろいろ聞かれるが基本的にYesで進めていけば良い。
2.matplotlibにimagemagicの場所を教える
お使いの環境のmatplotlibrc
というファイルを操作する。ファイルの場所を確かめるには以下のコマンドを実行すると良い。
import matplotlib matplotlib.matplotlib_fname()
例えば以下のような感じの場所に置いてある。
'C:\\<Python path>\\lib\\site-packages\\matplotlib\\mpl-data\\matplotlibrc'
そしたらメモ帳などで開いて,# animation.convert_path:
となっているところの#をはずしてコメントアウトを解除し,
animation.convert_path: C:\Program Files\ImageMagick-7.0.1-Q16\magick.exe #みんなの環境だと多分違うぞ
のようにimagemagicのexeファイルのパスを与える。(エクスプローラから自分で調べること!)
ArtistAnimationで図を作成
ArtistAnimationの図の作り方は非常にわかりやすく,matlabのようにplot情報をリストに入れていき,最後にそれらをつなげて動画にする。 自分でもコードなど書いたが,こちらのブログが大変わかりやすく,自分で書くまでもないと思ったのでコードを借りて以下に表記する。どうもありがとうございます。
import numpy as np import matplotlib.pyplot as plt import matplotlib.animation as animation fig = plt.figure() #figure objectを取得. ax = fig.add_subplot(111) x = np.arange(0,10,1) ims = [] #Line2D objectを入れるリストを用意 for time in range(x.shape[0]): im = ax.plot(x[0:time] ,x[0:time] ** 2) #Line2D objectを取得 ims.append(im) #imsにappendする #ArtistAnimation機能で,imsの中の画像を繋ぎ合わせる. ani = animation.ArtistAnimation(fig, ims, interval = 100) #imagemagickを使って,gif画像を保存 ani.save("test.gif", writer="imagemagick")
FuncAnimationで動画を作成保存する
こちらは,Animationの生成規則を与えて,逐次これを計算させるものになる。先程と同様の方がわかりやすい解説を上げていてくださり,まずはこちらを試してみると良いだろう。
以下に軽く私の理解を述べておく。URL先のコードで以下のように呼ばれているFuncAnimationでは,
- 最初にキャンバスとなるfigureのハンドル
fig
をわたし - 逐次処理を実行する
update()
関数を渡す - updateに渡す引数を決める
fargs
というのがオプションで存在し, - 画像間のinterval時間
- 最大繰り返しフレーム数
frames
を渡す
ani = animation.FuncAnimation(fig, update, fargs = (x, y, ax1, ax2), interval = 100, frames = 10)
という風になっている。従ってframeが0から9に至るまで,すなわち,
for i in range(frame): update(i,args)
という感じになっているはず。
この他にもinit()
という初期化関数を渡したりできる。
自分Verとしては例えば以下のようなものになる。ただし,ランダムな点をPlotしようとするので挙動はきっとクソ。 (Originalではちゃんとplotすべきデータがあったが簡略化させていただいた)
fig, ax = plt.subplots() line, = ax.plot([], [], 'r',label='trajectory') line2, = ax.plot([], [], 'kx',label='current position') ax.grid() xdata, ydata = [], [] plt.xlabel('x [m]') plt.ylabel('y [m]') plt.grid ='on' #def data_gen(): data = [[x[0],x[1]] for x in np.random.rand(100,2)] def init(): ax.set_ylim(-0.2, 1.2) ax.set_xlim(-1.2, 0.2) line.set_data(xdata, ydata) #line2.set_data(xdata, ydata) return line, def run(i): # update the data x, y = data[i] xdata.append(x) ydata.append(y) line.set_data(xdata, ydata) line2.set_data(x,y) plt.legend(loc='upper left') ani = FuncAnimation(fig, run, blit=False, interval=10, frames = int(len(data))-1, repeat=False, init_func=init) ani.save("plot2.gif",writer='imagemagick') plt.show()