はじめに
matplotlibのFuncAnimationで3次元のランダムウォークアニメーションを表示する。
コード
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#3d
%matplotlib inline
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.animation as animation
from IPython.display import HTML
from mpl_toolkits.mplot3d import Axes3D
theta=np.pi*np.random.random(499)
phi = 2.0 * np.pi*np.random.random(499)
x = np.sin(theta)*np.cos(phi)
y = np.cos(theta)*np.sin(phi)
z = np.cos(theta)
xyz = np.vstack((x,y,z)).T
norm_xyz = np.linalg.norm(xyz,axis=1)
xyz = xyz/norm_xyz[:,np.newaxis]
xyz = np.vstack(([[0,0,0]],xyz))
position_x = np.cumsum(xyz[:,0]) #累積和 x
position_y = np.cumsum(xyz[:,1]) #累積和 y
position_z = np.cumsum(xyz[:,2]) #累積和 z
fig = plt.figure(figsize=(6,6))
ax = fig.gca(projection='3d')
ax.set_box_aspect((1,1,1))
ax.plot(position_x,position_y, position_z, 'C6o-', alpha=0.5)
plt.show()
xlim = ax.get_xlim()
ylim = ax.get_ylim()
zlim = ax.get_zlim()
fig = plt.figure(figsize=(6,6))
ax = fig.gca(projection='3d')
p1, = ax.plot([], [], [],'o',color='C6', alpha=0.25)
ax.set_box_aspect((1,1,1))
ax.set(xlim=xlim,ylim=ylim,zlim=zlim)
def update(i):
p1.set_data((position_x[:i],position_y[:i]))
p1.set_3d_properties(position_z[:i])
return fig,
ani = animation.FuncAnimation(fig, update, 500,interval=20, blit=True)
ani.save('rw3d_anim.mp4', writer="ffmpeg",dpi=100)
HTML(ani.to_html5_video())
解説
モジュールのインポート
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#3d
%matplotlib inline
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.animation as animation
from IPython.display import HTML
from mpl_toolkits.mplot3d import Axes3D
3Dグラフなので from mpl_toolkits.mplot3d import Axes3D
とする。
バージョン
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#version
import matplotlib
print(matplotlib.__version__)
3.3.3
print(np.__version__)
1.19.5
データの生成
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
theta=np.pi*np.random.random(499)
phi = 2.0 * np.pi*np.random.random(499)
x = np.sin(theta)*np.cos(phi)
y = np.cos(theta)*np.sin(phi)
z = np.cos(theta)
xyz = np.vstack((x,y,z)).T
norm_xyz = np.linalg.norm(xyz,axis=1)
xyz = xyz/norm_xyz[:,np.newaxis]
xyz = np.vstack(([[0,0,0]],xyz))
position_x = np.cumsum(xyz[:,0]) #累積和 x
position_y = np.cumsum(xyz[:,1]) #累積和 y
position_z = np.cumsum(xyz[:,2]) #累積和 z
3次元のx,y,zデータを極座標系で媒介変数によって生成する。このデータ生成方法は下記でも用いた。

x,y,zをvstackでひとまとめにし、.Tによって転置する。
np.linalg.norm()でaxis=1とすることで各行における要素のノルムを求める。
求めたノルムで各要素をわることで各行の要素を規格化する。
np.vstack(([[0,0,0]],xyz))によりスタート地点を[0,0,0]とした。
positionは下記の1Dランダムウォーク、2Dランダムウォークの例と同様にnp.cumsum()により、累積和とすることで順次変化するランダムウォークの位置を取得した。


3次元のランダムウォークデータの表示
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
fig = plt.figure(figsize=(6,6))
ax = fig.gca(projection='3d')
ax.set_box_aspect((1,1,1))
ax.plot(position_x,position_y, position_z, 'C6o-', alpha=0.5)
plt.show()
上記で作成したデータを表示すると以下のようになる。

This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
xlim = ax.get_xlim()
ylim = ax.get_ylim()
zlim = ax.get_zlim()
上の図のx軸、y軸、z軸の表示範囲をax.get_xlim(), ax.get_ylim(), ax.get_zlim()で取得する。
アニメーションの表示
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
fig = plt.figure(figsize=(6,6))
ax = fig.gca(projection='3d')
p1, = ax.plot([], [], [],'o',color='C6', alpha=0.25)
ax.set_box_aspect((1,1,1))
ax.set(xlim=xlim,ylim=ylim,zlim=zlim)
def update(i):
p1.set_data((position_x[:i],position_y[:i]))
p1.set_3d_properties(position_z[:i])
return fig,
ani = animation.FuncAnimation(fig, update, 500,interval=20, blit=True)
ani.save('rw3d_anim.mp4', writer="ffmpeg",dpi=100)
HTML(ani.to_html5_video())
p1,で空のプロットを作成して、データを流し込んでいく。
x,yデータのセットには、set_dataを用いる。zデータのセットには、set_3d_propertiesを用いる。
x軸, y軸、z軸の表示範囲は、ax.set(xlim=xlim, ylim=ylim, zlim=zlim)のようにして先程取得したものを用いる。
ani = animation.FuncAnimationとし、このaniをHTML(ani.to_html5_video())とすることでjupyter lab(notebookも)上でアニメーションを表示できる。
コードをダウンロード(.pyファイル) コードをダウンロード(.ipynbファイル)
コメント