matplotlibによるサイクロイドのアニメーションにて
以下のサイトを参考に、matplotlibでグラフのアニメーション化を試してみた。
・matplotlibでランダムウォークをアニメーション - Soleil cou coupé
・Simple Animated Plot with Matplotlib | Scientific Python Script Repository
・Drawing and Animating Shapes with Matplotlib — nickcharlton.net
具体的な構造についてはよく分からないけど、まあ、ジェネレータがフレーム毎に呼ばれて値を返し、その値を毎回プロットすれば良い。
- アニメーションが表示されるパレットfigを用意する。
- obj,=ax.plot([ ],[ ])でアニメーションで動く変数objを用意する。
- ジェネレータgen()が呼ばれてdataを返す。例えば、x,y。
- obj.set_data(x,y)で値をobjにセット。
- 値がプロットされ、3に戻る。
これがジェネレータが終了するまで続く感じ。必要ならばfigも途中で再定義可能。
4の中身はfunc(data)内に記述。それらをまとめるanimation.FuncAnimation(fig,func,gen)でアニメーションが出力される。
ソースコード
さて、サイクロイドが何かというのは他の人にまかせて、その媒介変数表示は半径R、回転角θのとき
x=R(θ-sinθ), y=R(1-cosθ)
なので、これをθに対して動かすコードは次のようになる。
# -*- coding:utf-8 -*- from matplotlib import pyplot as plt from matplotlib import animation import numpy as np def circle(a, b, r): # 点(a,b)を中心とする半径rの円 T = 100 x, y = [0]*T, [0]*T for i,theta in enumerate(np.linspace(0,2*np.pi,T)): x[i] = a + r*np.cos(theta) y[i] = b + r*np.sin(theta) return x, y R = 1 def gen(): for theta in np.linspace(0,4*np.pi,100): yield R*(theta-np.sin(theta)), R*(1-np.cos(theta)), R*theta fig = plt.figure() ax = fig.add_subplot(111) ax.set_ylim(-5, 5) ax.set_xlim(0, 10) ax.set_xlabel('x') ax.set_ylabel('y') ax.grid() time_text = ax.text(0.05, 0.9, '', transform=ax.transAxes) cycloid, = ax.plot([], [], 'r-', lw=2) line, = ax.plot([], [], 'y-', lw=2) circle_line, = ax.plot([], [], 'g', lw=2) point, = ax.plot([], [], 'bo', ms=4) xx, yy = [], [] def func(data): x, y, Rt = data time_text.set_text('theta = %.2f pi' % (Rt/np.pi)) xx.append(x) yy.append(y) cx, cy = circle(Rt, R, R) cycloid.set_data(xx, yy) line.set_data((x,Rt), (y,R)) circle_line.set_data(cx, cy) point.set_data(x, y) ani = animation.FuncAnimation(fig, func, gen, blit=False, interval=100, repeat=False) #ani.save("cycloid.mp4") plt.show()
gifアニメ化
生成されたcycloid.mp4は
ffmpeg -i cycloid.mp4 -r 10 output%05d.png convert output*.png cycloid.gif rm output*.png
でgifアニメにできる。※手元の環境ではconvertが非常に重くて一度フリーズした。
よく分からないけどMP4ファイルではなく最初から連番pngを吐かせることも出来るはず。gif化ももっと手軽に使えるフリーソフトがあると思う。