Plotly
Plotly はインタラクティブなグラフを描くライブラリである.マウスでの回転・拡大や,アニメーションの再生ができる. 作成した図は Colab・JupyterLab でも,ビルド後の Web ページ上でも同じように動作するため,本演習ではインタラクティブな可視化・アニメーションの標準として用いる.
graph_objects を go という別名で読み込む.
import numpy as np
import plotly.graph_objects as go基本:折れ線・散布図¶
go.Figure に描画要素(トレース)を渡して図を作り,fig.show() で表示する.
折れ線・散布図には go.Scatter を使い,mode で線・点を切り替える.
x = np.linspace(0, 2 * np.pi, 100)
fig = go.Figure()
fig.add_trace(go.Scatter(x=x, y=np.sin(x), mode="lines", name="sin"))
fig.add_trace(go.Scatter(x=x, y=np.cos(x), mode="lines", name="cos"))
fig.update_layout(title="sin and cos", xaxis_title="x", yaxis_title="y")
fig.show()2次元の場:ヒートマップ¶
格子上のスカラー場は go.Heatmap で色として可視化できる.セルオートマトンや拡散場の表示に使う.
grid = np.linspace(-3, 3, 60)
X, Y = np.meshgrid(grid, grid)
Z = np.exp(-(X**2 + Y**2))
fig = go.Figure(go.Heatmap(z=Z))
fig.update_layout(title="2D Gaussian", width=500, height=500)
fig.show()格子・画像として表示する¶
セルオートマトン(P2-02)や拡散場(P2-03)のように,ヒートマップを「格子(画像)」として見せたいことがある. そのときは,セルを正方形にし,行0を上に表示し,必要なら配色を2値・離散にする.
# 2値の格子(例:市松模様)
grid = np.indices((8, 8)).sum(axis=0) % 2
fig = go.Figure(go.Heatmap(z=grid, colorscale="Greys", zmin=0, zmax=1, showscale=False))
fig.update_layout(
width=400,
height=400,
yaxis={"scaleanchor": "x", "autorange": "reversed"}, # 正方形のセル・行0を上に
title="binary grid",
)
fig.show()yaxisのscaleanchor="x"は y 軸の1単位を x 軸にそろえ,セルを正方形にする.autorange="reversed"は行0を上に表示する(既定では下).matshowや画像と同じ向きになる.colorscale="Greys"とzmin=0, zmax=1で 0 を白・1 を黒に対応させ,showscale=Falseでカラーバーを消す.
3次元:曲面と散布¶
go.Surface は3次元の曲面を描く.update_layout の scene で見た目を整える.
aspectmode="data" はデータの比率を保ち,形態の可視化(P2-01)で重要になる.
fig = go.Figure(go.Surface(x=X, y=Y, z=Z, showscale=False))
fig.update_layout(scene={"aspectmode": "data"}, title="3D surface")
fig.show()3次元の点群は go.Scatter3d で描ける.
theta = np.linspace(0, 6 * np.pi, 200)
fig = go.Figure(go.Scatter3d(x=np.cos(theta), y=np.sin(theta), z=theta, mode="lines"))
fig.update_layout(scene={"aspectmode": "data"}, title="helix")
fig.show()アニメーション¶
時間発展するシミュレーション(セルオートマトンや拡散)は,各時刻の状態をフレーム (frame)として並べてアニメーションにする.
go.Frame のリストを frames に渡し,再生ボタンとスライダーを付ける.このパターンを P2-02・P2-03 でそのまま使う.
まず,各時刻の場(2次元配列)のリストを用意する(ここでは広がるガウス分布).
fields = []
for t in np.linspace(0.3, 2.5, 30):
fields.append(np.exp(-(X**2 + Y**2) / (2 * t**2)))各フレームを go.Frame にして図を組み立てる.
再生速度は「1フレームあたりの表示時間(ミリ秒)」で決まる.速度の異なる再生ボタンを複数用意しておくと切り替えられて便利である.
frames = [
go.Frame(data=[go.Heatmap(z=f, zmin=0, zmax=1)], name=str(k))
for k, f in enumerate(fields)
]
fig = go.Figure(data=[go.Heatmap(z=fields[0], zmin=0, zmax=1)], frames=frames)
def play_button(label, duration):
"""1フレームを duration ミリ秒で表示して再生するボタン(小さいほど速い)"""
return {
"label": label,
"method": "animate",
"args": [
None,
{
"frame": {"duration": duration, "redraw": True},
"fromcurrent": True,
"transition": {"duration": 0},
},
],
}
fig.update_layout(
width=600,
height=640,
margin={"l": 20, "r": 20, "t": 70, "b": 20},
updatemenus=[
{
"type": "buttons",
"direction": "right",
"showactive": False,
"x": 0.5,
"xanchor": "center",
"y": 1.1,
"yanchor": "bottom",
"buttons": [
play_button("Play", 120),
play_button("Fast", 40),
play_button("Slow", 300),
{
"label": "Pause",
"method": "animate",
"args": [[None], {"frame": {"duration": 0}, "mode": "immediate"}],
},
],
}
],
# スライダー(フレームを手動で選ぶ)
sliders=[
{
"steps": [
{"label": str(k), "method": "animate", "args": [[str(k)]]}
for k in range(len(frames))
]
}
],
)
fig.show()Play/Fast/Slow で再生速度を切り替えられ,スライダーで任意の時刻に移動できる(redraw=True はヒートマップの更新に必要).
2次元配列のリスト fields を差し替えるだけで,さまざまなシミュレーションの可視化に応用できる.
応用:格子のアニメーション¶
上のフレーム (frame)の仕組みに,「格子・画像として表示する」設定を重ねるだけで,セルオートマトンや拡散場の時間発展を可視化できる.
各フレームの go.Heatmap を2値配色にし,layout に正方形・反転を加える.
# 各世代の2値の場(例:対角に動く点)
size = 20
grids = [np.zeros((size, size), dtype=int) for _ in range(size)]
for t in range(size):
grids[t][t, t] = 1
frames = [
go.Frame(
data=[go.Heatmap(z=g, colorscale="Greys", zmin=0, zmax=1, showscale=False)],
name=str(k),
)
for k, g in enumerate(grids)
]
fig = go.Figure(
data=[go.Heatmap(z=grids[0], colorscale="Greys", zmin=0, zmax=1, showscale=False)],
frames=frames,
)
fig.update_layout(
width=460,
height=520,
yaxis={"scaleanchor": "x", "autorange": "reversed"}, # 正方形のセル・行0を上に
updatemenus=[
{
"type": "buttons",
"buttons": [play_button("Play", 200), play_button("Slow", 400)],
}
],
)
fig.show()各世代の2次元配列を並べた grids を差し替えるだけで,P2-02(セルオートマトン,2値)にも P2-03(反応拡散,連続的な配色)にも応用できる.
速度ボタンやスライダーは前節と同じ要領で増やせる.