はじめに
plotlyでスライダー付きグラフをよく作成するのでメモです。
1つのプロットをスライダーで動かすのは公式にコードが乗っているので、複数同時に動かしたい時などのちょっとした応用を記載します。
公式サイト(スライダーの説明ページ)
Sliders | Python | Plotly
環境
Mac OS
python 3.8.5
plotly 4.12.0
pip, import
pipから以下をインストールします。記事でnumpyを使用する為一緒にインストールしています。
pip install plotly
pip install numpy
import numpy as np
import plotly.offline as offline
import plotly.graph_objs as go
plotly スライダーの基本
公式にも載っていますが、一応
See the Pen simple slider by shunta-m (@shunta-m) on CodePen.
trace(プロット)作成 -> レイアウト作成 -> グラフ作成の順で書いています
import numpy as np
import plotly.offline as offline
import plotly.graph_objs as go
# プロットを保存するリスト
data = []
x = np.linspace(0, 10, 101)
# プロットの作成
# 0, 0.1, ... , 5までのプロットを作成する
for step in np.linspace(0, 5, 51):
y = np.sin(step * x)
trace = go.Scatter(
x=x,
y=y,
name="sin step{:.1f}".format(step),
line=dict(color="red", width=3),
visible=False, ) # 見えない状態にする
data.append(trace)
# 初期状態として、10番目のプロットを見えるようにしておく
data[10].visible = True
# スライダーの位置によってどこを表示/非表示にするかを保存するリスト
steps = []
"""
for文内でどこを見えるようにするか決めている
例えばスライダーが10にいる時、10番目のプロットが見えればいいので
一度全てを非表示 -> 10番目プロットのvisibleをTrueにして見えるようにする
"""
for s in range(len(data)):
step = dict(method="update",
args=[{"visible": [False] * len(data)}, # 一度全て非表示
{"title": "Simple slider step: {}".format(s)}] # スライダーの位置によってタイトルも変更する
)
step["args"][0]["visible"][s] = True # 対応するものだけを見えるようにする
# ↑で作ったs番目だけが見えるレイアウトをstepsに追加
steps.append(step)
sliders = [dict(
active=10, # スライダーの初期値
currentvalue=dict(prefix="Frequency: "),
pad=dict(t=50), # スライダーの占有範囲, 数値を大きくする程スライダーの範囲が大きくなる
steps=steps)] # stepsが持っている表示/非表示の情報を使う
layout = go.Layout(
title="Simple slider step: 10", # 初期状態のタイトル
xaxis=dict(title="x"),
yaxis=dict(title="y"),
font=dict(family="Meiryo", size=16), # グラフ内のフォントをメイリオ、サイズを16へ
# ホバーモード(グラフにカーソルを近づけた時の数値の見え方)の設定
# 与えることができる文字列は "x", "y", "closest", False, "x unified", "y unified"
hovermode="x unified",
hoverlabel=dict(font_size=16), # ホバーモードの文字サイズ設定
sliders=sliders, # スライダー追加
showlegend=True) # 凡例表示をTrueに
fig = dict(data=data, layout=layout)
# 出力
offline.plot(fig, auto_open=True, include_plotlyjs="cdn", filename="simple_slider.html")
複数プロットを動かす
sin波、cos波を両方動かしてみます。
import numpy as np
import plotly.offline as offline
import plotly.graph_objs as go
# sin, cos波のtraceをを別々に保存
sin_data, cos_data = [], []
x = np.linspace(0, 10, 101)
for step in np.linspace(0, 5, 51):
y = np.sin(step * x)
y2 = np.cos(step * x)
sin_trace = go.Scatter(
x=x,
y=y,
name="sin {:.1f}Hz".format(step),
line=dict(color="red", width=3),
visible=False, )
cos_trace = go.Scatter(
x=x,
y=y2,
name="cos {:.1f}Hz".format(step),
line=dict(color="blue", width=3),
visible=False, )
sin_data.append(sin_trace)
cos_data.append(cos_trace)
sin_data[10].visible = True
cos_data[10].visible = True
data = sin_data + cos_data
steps = []
"""
sin_data, cos_dataの表示/非表示を別々に設定した後、結合してvisibleキーに追加
例えばスライダーが2の時、
sin_visible = [False, False, True, False,...]
cos_visible = [False, False, True, False,...]
にした後2つを結合することで、sin, cos共に2番地目のtraceを表示できるようにする
"""
for s in range(len(sin_data)):
# sin_data, cos_data共に一度全て非表示にする
sin_visible, cos_visible = [False] * len(sin_data), [False] * len(cos_data)
# それぞれs番目だけ見えるようにする
sin_visible[s], cos_visible[s] = True, True
step = dict(method="update",
args=[{"visible": sin_visible + cos_visible},
{"title": "Simple slider step: {}".format(s)}]
)
steps.append(step)
sliders = [dict(
active=10,
currentvalue=dict(prefix="Frequency: "),
pad=dict(t=50),
steps=steps)]
layout = go.Layout(
title="Simple slider step: 10",
xaxis=dict(title="x"),
yaxis=dict(title="y"),
font=dict(family="Meiryo", size=16),
hovermode='x unified',
hoverlabel=dict(font_size=16),
sliders=sliders,
showlegend=True)
fig = dict(data=data, layout=layout)
offline.plot(fig, include_plotlyjs="cdn", filename="plots.html")
一部プロットを動かす
同じグラフ内にスライダーで動かしたいもの、動かしたくないものがある時
import numpy as np
import plotly.offline as offline
import plotly.graph_objs as go
data = []
sin_data, cos_data = [], []
x = np.linspace(0, 10, 101)
# 固定プロット
trace = go.Scatter(
x=x,
y=2 * np.cos(x),
name="2 * cos",
line=dict(color="green", width=3),
visible=True, )
data.append(trace) # dataの0番目が固定プロット情報
# スライダープロット
for step in np.linspace(0, 5, 51):
y = np.sin(step * x)
y2 = np.cos(step * x)
sin_trace = go.Scatter(
x=x,
y=y,
name="sin {:.1f}Hz".format(step),
line=dict(color="red", width=3),
visible=False, )
cos_trace = go.Scatter(
x=x,
y=y2,
name="cos {:.1f}Hz".format(step),
line=dict(color="blue", width=3),
visible=False, )
sin_data.append(sin_trace)
cos_data.append(cos_trace)
sin_data[10].visible = True
cos_data[10].visible = True
data += sin_data + cos_data
steps = []
"""
固定プロットは常に表示すればいいので、visibleを常にTrueにする
->dataの0番目(固定プロット)をTrueにする
"""
for s in range(len(sin_data)):
sin_visible, cos_visible = [False] * len(sin_data), [False] * len(cos_data)
sin_visible[s], cos_visible[s] = True, True
step = dict(method="update",
args=[{"visible": [True] + sin_visible + cos_visible}, # 0番目は常にTrue
{"title": "Simple slider step: {}".format(s)}]
)
steps.append(step)
sliders = [dict(
active=10,
currentvalue=dict(prefix="Frequency: "),
pad=dict(t=50),
steps=steps)]
layout = go.Layout(
title="Simple slider step: 10",
xaxis=dict(title="x"),
yaxis=dict(title="y"),
font=dict(family="Meiryo", size=16),
hovermode='x unified',
hoverlabel=dict(font_size=16),
sliders=sliders,
showlegend=True)
fig = dict(data=data, layout=layout)
offline.plot(fig, include_plotlyjs="cdn", filename="plot2.html")
途中から非表示にする
スライダーが40以上になるとcosが消えます。
単純に40以上の時cos_traceのx, yの値をNoneにしています。
import numpy as np
import plotly.offline as offline
import plotly.graph_objs as go
x = np.linspace(0, 10, 101)
data = []
sin_data, cos_data = [], []
trace = go.Scatter(
x=x,
y=2 * np.cos(x),
name="2 * cos",
line=dict(color="green", width=3),
visible=True, )
data.append(trace)
for step in np.linspace(0, 5, 51):
y = np.sin(step * x)
y2 = np.cos(step * x)
sin_trace = go.Scatter(
x=x,
y=y,
name="sin {:.1f}Hz".format(step),
line=dict(color="red", width=3),
visible=False, )
if step < 4:
cos_trace = go.Scatter(
x=x,
y=y2,
name="cos {:.1f}Hz".format(step),
line=dict(color="blue", width=3),
visible=False, )
else:
cos_trace = go.Scatter(x=None, y=None) # 4以上はNone
sin_data.append(sin_trace)
cos_data.append(cos_trace)
sin_data[10].visible = True
cos_data[10].visible = True
data += sin_data + cos_data
steps = []
for s in range(len(sin_data)):
sin_visible, cos_visible = [False] * len(sin_data), [False] * len(cos_data)
sin_visible[s], cos_visible[s] = True, True
step = dict(method="update",
args=[{"visible": [True] + sin_visible + cos_visible},
{"title": "Simple slider step: {}".format(s)}]
)
steps.append(step)
sliders = [dict(
active=10,
currentvalue=dict(prefix="Frequency: "),
pad=dict(t=50),
steps=steps)]
layout = go.Layout(
title="Simple slider step: 10",
xaxis=dict(title="x"),
yaxis=dict(title="y"),
font=dict(family="Meiryo", size=16),
hovermode='x unified',
hoverlabel=dict(font_size=16),
sliders=sliders,
showlegend=True)
fig = dict(data=data, layout=layout)
offline.plot(fig, include_plotlyjs="cdn", filename="plots3.html")
参考サイト
公式サイト
Plotly Python Graphing Library | Python | Plotly
codepen
Plotlyを使った描画結果をQiita内にCodePen埋め込むことで確認する - Qiita
Qiitaで記事にCodePenが埋め込めるようになりました - Qiita