Python matplotlib animationで遊ぶ

POINT

  • Pythonでアニメーションを作成する方法.
  • 数値計算の結果の描画などに利用できる.
  • 公開されているサンプルコードを少しいじって,挙動を確認した.

Pythonでアニメーションを作成できることを知りました.二重振り子の微分方程式を解き,その運動をアニメーションとして可視化する簡単なサンプルコードが公開されています.練習のために少しいじって挙動を確認しました.

軌跡の描画

まずは,簡単な軌跡を描画してみました.コードと出力されたアニメーションを見比べることにより,

  • 動かさない部分(軌跡)をどう書くか
  • 2点を線で結ぶにはどうするか
  • 3点を線で結ぶにはどうするか

が確認できると思います.

Python matplotlib.animationで描画した軌跡
Python matplotlib.animationで描画した軌跡

from numpy import sin, cos
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation

# create data
t_min = 0
t_max = 20
dt = 0.05
t = np.arange(t_min, t_max + dt, dt)

a = 2

x1 = sin(t)
x2 = a*sin(t)

y1 = a*cos(t)
y2 = -cos(t)

# plot
fig = plt.figure()
ax = fig.add_subplot(111, autoscale_on=False, xlim=(-2, 2), ylim=(-2, 2))
ax.set_aspect('equal')
ax.grid()

ax.plot(x1, y1, ':c', markersize=1)
ax.plot(x2, y2, '*m', markersize=1)

line1, = ax.plot([], [], 'o-b', lw=2)
line2, = ax.plot([], [], 'x-.g', lw=2)
time_template = 'time = %.1fs'
time_text = ax.text(0.05, 0.9, '', transform=ax.transAxes)


def init():
    line1.set_data([], [])
    line2.set_data([], [])
    time_text.set_text('')
    return line1, line2, time_text


def animate(i):
    thisx_line1 = [0, x1[i], x2[i]]
    thisy_line1 = [0, y1[i], y2[i]]

    thisx_line2 = [0, x2[i]]
    thisy_line2 = [0, y2[i]]

    line1.set_data(thisx_line1, thisy_line1)
    line2.set_data(thisx_line2, thisy_line2)
    time_text.set_text(time_template % (i*dt))
    return line1, line2, time_text


ani = animation.FuncAnimation(fig, animate, np.arange(0, len(t)),
                              interval=25, blit=True, init_func=init)

ani.save('simple_animation.mp4', fps=15)
ani.save('simple_animation.gif', fps=15, writer='pillow')
plt.show()

グラフと点を動かす

コードと出力されたアニメーションを見比べることにより,

  • 正弦波の動かし方
  • 点の動かし方

が確認できます.

Python matplotlib.animationで正弦波を動かす
Python matplotlib.animationで正弦波を動かす

from numpy import sin, cos, pi
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation

# create data
c = 0.1 * 2*pi


def wave(x, t):
    y = sin(x - c*t)
    return y


t_min = 0
t_max = 20
dt = 0.05
t = np.arange(t_min, t_max + dt, dt)

x_min = -2*pi
x_max = 2*pi
dx = 0.05
x = np.arange(x_min, x_max + dx, dx)

# plot
fig = plt.figure()
ax = fig.add_subplot(111, autoscale_on=False,
                     xlim=(x_min, x_max), ylim=(-2, 2))
ax.set_aspect('equal')
ax.grid()

ax.plot(x, wave(x, t_min), '-.b', lw=1)

line, = ax.plot([], [], '-b', lw=2)
point, = ax.plot([], [], '*r', markersize=10)
time_template = 'time = %.1fs'
time_text = ax.text(0.05, 0.9, '', transform=ax.transAxes)


def init():
    line.set_data([], [])
    point.set_data([], [])
    time_text.set_text('')
    return line, point, time_text


def animate(i):
    lx = x
    ly = wave(x, i*dt)

    px = c*i*dt / 2
    py = wave(px, i*dt)

    line.set_data(lx, ly)
    point.set_data(px, py)
    time_text.set_text(time_template % (i*dt))
    return line, point, time_text


ani = animation.FuncAnimation(fig, animate, np.arange(0, len(t)),
                              interval=25, blit=True, init_func=init)

ani.save('sinwave_animation.mp4', fps=15)
ani.save('sinwave_animation.gif', fps=15, writer='pillow')
plt.show()