こんな人にオススメ
plotly
ってグラフ内にボタンをつけて、そのボタンでプロットを表示したりできるらしいじゃん。
どうやったら実装できる?
ということで、今回はplotly
のボタン機能を実装する方法を、go
を使用して解説する。ボタンを使用すると簡単にグラフの表示・非表示やグラフの見た目を変更可能。
例えば以下の記事ではボタンを使用してデータ・グラフの切り替えを行なっている。
-
-
【ノイキャン対応の完全ワイヤレスイヤホンレビュー】レーダーチャート、棒グラフで比較
続きを見る
-
-
【plotly&legendまとめ】凡例の引数一覧
続きを見る
ボタン機能の基本的な考え方は、予めボタンに対応するグラフの表示・非表示を組み込んで、ボタンを押したら呼び出すというもの。ボタンを押すごとに計算しているわけではない。
なので、一回グラフを作成して保存してしまえば、オフラインでも使用できる。
python環境は以下。
- Python 3.10.1
- numpy 1.21.4
- plotly 5.4.0
- plotly-orca 3.4.2
- webcolors 1.11.1
なお、新しく立ち上げたサイト「Pro天パ」ではリライト(書き直し)した記事を公開している。併せてご覧いただきたい。
作成したコード全文
下準備(import
)
import numpy as np import plotly.graph_objects as go import plotly.io as pio import webcolors
まずは下準備としてのimport
関連。numpy
はデータを作成する際に使用。go
でグラフを作成し、pio
でグラフを保存。go
で散布図を描く方法、pio
でグラフを保存する方法については以下参照。
-
-
【plotly&go.Scatter】plotlyの散布図グラフの描き方
続きを見る
-
-
【plotly&orca】plotlyで静止画保存(orca)
続きを見る
最後のwebcolors
は’red’
や’blue’
といったカラーコードを、(255, 0, 0)
、(0, 0, 255)
といったRGB形式に変換するためのライブラリ。不透明度を変更する際に使用するが、そもそもRGBを使用するなら必要ない。
ボタンなしのグラフ
まずはボタンなしのシンプルなグラフを作成。単に2種類のプロットを1つのグラフに並べた。今回はgo.Scater
で散布図を作成したが、go
の散布図については以下参照。
-
-
【plotly&go.Scatter】plotlyの散布図グラフの描き方
続きを見る
2種類のプロット程度なら同時にプロットしても問題ない。予めグループを設定しておき、それらを切り替えたいってなるとボタン機能があるとわかりやすい。
ということで、次からplotly
でボタンを設置する方法を解説する。
import plotly.graph_objects as go import plotly.io as pio # 2つのグラフをシンプルにグラフ化 x = (0, 1, 2, 3, 4) y1 = (0, 1, 4, 3, 2) y2 = (1, 3, 2, 4, 0) # 配列の要素にプロット内容を格納 plot = [ go.Scatter(x=x, y=y1, name='y1'), go.Scatter(x=x, y=y2, name='y2'), ] # レイアウトの作成 layout = go.Layout( title='title', # グラフタイトル font_size=20, # グラフ全体のフォントサイズ hoverlabel_font_size=20 # ホバーのフォントサイズ ) # グラフの表示 fig = go.Figure(data=plot, layout=layout) fig.show() # グラフの保存 prefix = 'plotly-buttons' save_name = f"{prefix}_wide_df" pio.orca.config.executable = '/Applications/orca.app/Contents/MacOS/orca' pio.write_html(fig, f"{save_name}.html") pio.write_image(fig, f"{save_name}.png")
グラフにボタンを設置
上のグラフでは上部にボタンを設置してy1
, y2
の表示を切り替えられるように設定した。ボタンの内容は以下。
all
:y1
,y2
どちらも表示y1
:y1
のみ表示y2
:y2
のみ表示
ボタンを押すことで上記の操作を可能にしているが、その作り方は以下の4ステップで構成されている。今回はわかりやすいようにステップごとにバラバラにコードを書いたが、layout
のupdatemenus
に直接、全ての処理に入れても問題ない。
- 各ボタン(
all
,y1
,y2
)の内容を設定:button_al
,button1
,button2
- 使用するボタンを全て配列にまとめる:
buttons
- レイアウトにボタンを設置するための設定を行う:
updatemenus
- グラフレイアウトの引数
updatemenus
に上記設定を適用:updatemenus
これらのステップで作成したコードが以下。次より上記ステップの解説を行う。
import plotly.graph_objects as go import plotly.io as pio # 2つのグラフを切り替えられるボタンを作成 x = (0, 1, 2, 3, 4) y1 = (0, 1, 4, 3, 2) y2 = (1, 3, 2, 4, 0) # 配列の要素にプロット内容を格納 plot = [ go.Scatter(x=x, y=y1, name='y1'), go.Scatter(x=x, y=y2, name='y2'), ] # 2プロット表示用のボタン作成 button_all = dict( label='all', # ボタンのラベル method='update', # ボタンの適用範囲はデータプロットとレイアウト args=[ dict(visible=[True, True]), # y1, y2の両方を表示 dict(title='all plots'), # グラフタイトル ] ) # y1表示用のボタン作成 button1 = dict( label='y1', # ボタンのラベル method='update', # ボタンの適用範囲はデータプロットとレイアウト args=[ dict(visible=[True, False]), # y1のみ表示 dict(title='y1 plot'), # グラフタイトル ] ) # y2表示用のボタン作成 button2 = dict( label='y2', # ボタンのラベル method='update', # ボタンの適用範囲はデータプロットとレイアウト args=[ dict(visible=[False, True]), # y2のみ表示 dict(title='y2 plot'), # グラフタイトル ] ) # ボタンをひとまとめにする buttons = [button_all, button1, button2] # レイアウトに設置するためのupdatemenus作成 updatemenus = [ dict( active=0, # 初期グラフで見た目上、押されるボタン type='buttons', # ボタンのタイプはボタンに direction='right', # ボタンは右向きに配置 x=0.5, y=1.01, # ボタンの位置 xanchor='center', yanchor='bottom', # ボタンの位置の基準 buttons=buttons, # ここに設定したボタン情報を入れる ) ] # レイアウトの作成 layout = go.Layout( title='title', # グラフタイトル font_size=20, # グラフ全体のフォントサイズ hoverlabel_font_size=20, # ホバーのフォントサイズ updatemenus=updatemenus, # ボタンを設置 ) # グラフの表示 fig = go.Figure(data=plot, layout=layout) fig.show() # グラフの保存 prefix = 'plotly-buttons' save_name = f"{prefix}_simple_buttons" pio.orca.config.executable = '/Applications/orca.app/Contents/MacOS/orca' pio.write_html(fig, f"{save_name}.html") pio.write_image(fig, f"{save_name}.png")
各ボタン(all
, y1
, y2
)の内容を設定
# 2プロット表示用のボタン作成 button_all = dict( label='all', # ボタンのラベル method='update', # ボタンの適用範囲はデータプロットとレイアウト args=[ dict(visible=[True, True]), # y1, y2の両方を表示 dict(title='all plots'), # グラフタイトル ] ) # y1表示用のボタン作成 button1 = dict( label='y1', # ボタンのラベル method='update', # ボタンの適用範囲はデータプロットとレイアウト args=[ dict(visible=[True, False]), # y1のみ表示 dict(title='y1 plot'), # グラフタイトル ] ) # y2表示用のボタン作成 button2 = dict( label='y2', # ボタンのラベル method='update', # ボタンの適用範囲はデータプロットとレイアウト args=[ dict(visible=[False, True]), # y2のみ表示 dict(title='y2 plot'), # グラフタイトル ] )
まずはボタンの内容。主に使用する引数は以下。
label
: ボタンに表示されるボタンラベルmethod
: クリック時にどの部分を変更するか'restyle'
: プロットだけ変更'relayout'
: レイアウトだけ変更'animate'
: アニメーションにする'update'
: プロットとレイアウト両方を変更'skip'
: 変更しない
args
: クリック時の動作- 1つ目の
dict
がプロット関連 - 2つ目の
dict
がレイアウト関連
- 1つ目の
label
はボタンラベルなのでわかりやすい名称にすると良い。method
も’update’
を指定しておけば、アニメーションにしない限りは問題ない。go
のアニメーションについては以下。
-
-
【Plotly&animation】Plotlyのgoでアニメーションを作成
続きを見る
args
は2つのdict
を格納したlist
で指定する。1つ目のdict
がプロット関連の内容で、ここではvisible
とすることでグラフの表示・非表示を指定している。True
が表示、False
が非表示だ。
このvisible
はプロットを作成した時の順番と同じ位置で指定する。ここではy1
→y2
の順番でプロットを作成したので、button1
は[True, False]
より、y1
を表示してy2
を非表示にする。
2つ目のdictはレイアウト関連の設定を入れる。ここではグラフタイトルを設定した。
使用するボタンを全て配列にまとめる
# ボタンをひとまとめにする buttons = [button_all, button1, button2]
これに関してはシンプルに、作成したボタンたちを1つの配列にまとめるだけ。今回は3つのボタンを作成したのでこれらをひとまとめにした。
レイアウトにボタンを設置するための設定を行う
# レイアウトに設置するためのupdatemenus作成 updatemenus = [ dict( active=0, # 初期グラフで見た目上、押されるボタン type='buttons', # ボタンのタイプはボタンに direction='right', # ボタンは右向きに配置 x=0.5, y=1.01, # ボタンの位置 xanchor='center', yanchor='bottom', # ボタンの位置の基準 buttons=buttons, # ここに設定したボタン情報を入れる ) ]
続いてはレイアウトに設置するための設定。各ボタンではなく、ボタン全体としてレイアウトにどのように設置するかを決める。主な引数は以下。
active
: グラフ作成時に見た目上どのボタンが押されているかtype
: ボタンタイプ。buttons
とdropdown
から選択direction
: ボタンを並べる方向。'left'
,'right'
,'up'
,'down’
より選択x
,y
: ボタンの位置xanchor
,yanchor
:x
,y
の基準。x=1,
xanchor=’right’
ならボタン右端がx=1
にくるbuttons
: 作成したボタンはここへpad
: 余白。t
,b
,l
,r
と数値で上下左右の余白を設定
active
はグラフの初期表示時にどのボタンが見た目の上で押されているかを決める。これはあくまでも見た目上の話で、例えばactive=1
でy1
のボタンが押されるようにするとおかしなことになる。
なぜなら、go.Scatter
作成時に全プロットを表示するようにしているから、ボタンはy1
が押されているのに見えているプロットはy1
, y2
となる。チグハグ。
なお、active=-1
に設定すると初期表示では見た目の上ではボタンは押されないようになる。
グラフレイアウトの引数updatemenus
に上記設定を適用
# レイアウトの作成 layout = go.Layout( title='title', # グラフタイトル font_size=20, # グラフ全体のフォントサイズ hoverlabel_font_size=20, # ホバーのフォントサイズ updatemenus=updatemenus, # ボタンを設置 )
最後に作成したボタン設定をレイアウトに反映させる。引数はupdatemenus
。今回はボタン設定の変数もupdatemenus
で作成したので、updatemenus=updatemenus
とする。
その他の引数についてはコメントアウトの通り。グラフタイトルとフォントサイズを変更している。
ドロップダウンのボタンを作成
続いてはボタン形式をドロップダウンにした場合のグラフだ。ドロップダウンにするには上で書いた変数updatemenus
の引数type
をtype=’dropdown’
にするだけ。
なお、direction=’right’
のままだと右側に出てきて押しづらかったので、type=’down’
にして下方向に展開されるように設定した。
import plotly.graph_objects as go import plotly.io as pio x = (0, 1, 2, 3, 4) y1 = (0, 1, 4, 3, 2) y2 = (1, 3, 2, 4, 0) # 配列の要素にプロット内容を格納 plot = [ go.Scatter(x=x, y=y1, name='y1'), go.Scatter(x=x, y=y2, name='y2'), ] # 2プロット表示用のボタン作成 button_all = dict( label='all', # ボタンのラベル method='update', # ボタンの適用範囲はデータプロットとレイアウト args=[ dict(visible=[True, True]), # y1, y2の両方を表示 dict(title='all plots'), # グラフタイトル ] ) # y1表示用のボタン作成 button1 = dict( label='y1', # ボタンのラベル method='update', # ボタンの適用範囲はデータプロットとレイアウト args=[ dict(visible=[True, False]), # y1のみ表示 dict(title='y1 plot'), # グラフタイトル ] ) # y2表示用のボタン作成 button2 = dict( label='y2', # ボタンのラベル method='update', # ボタンの適用範囲はデータプロットとレイアウト args=[ dict(visible=[False, True]), # y2のみ表示 dict(title='y2 plot'), # グラフタイトル ] ) # ボタンをひとまとめにする buttons = [button_all, button1, button2] # レイアウトに設置するためのupdatemenus作成 updatemenus = [ dict( active=-1, # -1にすると初期グラフでは見た目上ボタンは押されない type='dropdown', # ボタンのタイプはドロップダウン direction='down', # ボタンは下向きに配置 x=0.5, y=1.01, # ボタンの位置 xanchor='center', yanchor='bottom', # ボタンの位置の基準 buttons=buttons, # ここに設定したボタン情報を入れる ) ] # レイアウトの作成 layout = go.Layout( title='title', # グラフタイトル font_size=20, # グラフ全体のフォントサイズ hoverlabel_font_size=20, # ホバーのフォントサイズ updatemenus=updatemenus, # ボタンを設置 ) # グラフの表示 fig = go.Figure(data=plot, layout=layout) fig.show() # グラフの保存 prefix = 'plotly-buttons' save_name = f"{prefix}_simple_buttons_dropdown" pio.orca.config.executable = '/Applications/orca.app/Contents/MacOS/orca' pio.write_html(fig, f"{save_name}.html") pio.write_image(fig, f"{save_name}.png")
for
を使用してボタンを作成
できるグラフは同じだが、for文を使ってボタンを作成することももちろん可能。for文を使用することで、複数ボタンも短く書くことができる。先程の例だと3ボタンだったが、これが5ボタンとかになると面倒になるから楽をする。
なお、y1
, y2
はボタンのコードが似ているのでここをfor
文で書く。一方で、all
ボタンはコードの構造が少々異なるので、ここで統一感を出そうとするよりも初めから分けたほうが見やすくなる。
for
を使用する場合は以下のようにvisible
を操作する。
- 一旦、全プロット数だけの
False
を持つlistvisible
を作成 for
ループで表示したいプロットに該当するvisible
内のFalse
をTrue
に変更- 編集した
visible
をボタンに適用
以上を踏まえて作成したコードが以下。for
でplot
をenumerate
で数値num
を取得しながら回している。num
は何番目のvisible
をTrue
にするかという処理で使用。num=0
はy1
, num=1
はy2
に対応している。
また、plot
の各要素data
はprint(plot)
で出力される各go.Scatter
のこと。go.Scatter
はdict
のように扱うことができるので、data[’name’]
とすることでプロット名(y1
, y2
)を取り出せる。
仮にx
が欲しかったらdata[’x’]
にするとよいし、マーカーの色が欲しかったらdata[’marker’][’color’]
にするとよい。
import plotly.graph_objects as go import plotly.io as pio # forを使って短く描く x = (0, 1, 2, 3, 4) y1 = (0, 1, 4, 3, 2) y2 = (1, 3, 2, 4, 0) # 配列の要素にプロット内容を格納 plot = [ go.Scatter(x=x, y=y1, name='y1'), go.Scatter(x=x, y=y2, name='y2'), ] print(plot) # [Scatter({ # 'name': 'y1', 'x': [0, 1, 2, 3, 4], 'y': [0, 1, 4, 3, 2] # }), Scatter({ # 'name': 'y2', 'x': [0, 1, 2, 3, 4], 'y': [1, 3, 2, 4, 0] # })] # 2プロット表示用のボタン作成 button_all = dict( label='all', # ボタンのラベル method='update', # ボタンの適用範囲はデータプロットとレイアウト args=[ dict(visible=[True, True]), # y1, y2の両方を表示 dict(title='all plots'), # グラフタイトル ] ) # 2プロット表示用のボタンを先に入れる buttons = [button_all] # forを使ってボタン作成を短く書く for num, data in enumerate(plot): # 一旦全てのプロットを非表示にしてから、該当するプロットを表示変更 visible = [False] * len(plot) visible[num] = [True] # ボタン作成 button = dict( label=data['name'], # ボタンのラベル method='update', # ボタンの適用範囲はデータプロットとレイアウト args=[ dict(visible=visible), # y1のみ表示 dict(title=f"{data['name']} plot"), # グラフタイトル ] ) buttons.append(button) # レイアウトに設置するためのupdatemenus作成 updatemenus = [ dict( active=0, # 初期グラフで見た目上、押されるボタン type='buttons', # ボタンのタイプはボタンに direction='right', # ボタンは右向きに配置 x=0.5, y=1.01, # ボタンの位置 xanchor='center', yanchor='bottom', # ボタンの位置の基準 buttons=buttons, # ここに設定したボタン情報を入れる ) ] # レイアウトの作成 layout = go.Layout( title='title', # グラフタイトル font_size=20, # グラフ全体のフォントサイズ hoverlabel_font_size=20, # ホバーのフォントサイズ updatemenus=updatemenus, # ボタンを設置 ) # グラフの表示 fig = go.Figure(data=plot, layout=layout) fig.show() # グラフの保存 prefix = 'plotly-buttons' save_name = f"{prefix}_simple_buttons_for" pio.orca.config.executable = '/Applications/orca.app/Contents/MacOS/orca' pio.write_html(fig, f"{save_name}.html") pio.write_image(fig, f"{save_name}.png")
5データのグラフで少し応用
やっていることは大差ないが、ここではデータ数を増やして合計5データとした。今回はy = ax + bの直線のグラフのうち、bの部分を増やしてグラフを作成。
先程のy1
, y2
のグラフからの変更点は以下。
marker_color
プロットの色を指定sholegend=True
でボタン操作で1プロットになっても凡例が消えないようにxaxis_range
,yaxis_range
で横軸・縦軸の表示範囲を固定legend=dict(...)
で凡例をプロット領域の右端に移動
先程のy1
, y2
にグラフだとボタンを押してy1
, y2
だけにすると、凡例が消えるしプロットの色も変更された。今回はこれを防ぐために凡例の常時表示と色指定をした。
また、グラフの表示範囲を固定することで、プロットが変わった時の自動表示範囲変更を防いでいる。そして蛇足だが凡例の位置も変更した。
なお、ボタンはfor
文を使って短く作成。ボタンが合計で6つもあるのでfor
で短く書きたい。
import numpy as np import plotly.graph_objects as go import plotly.io as pio x = np.arange(5) ys = {} for num in range(5): y = x + num # y = ax + bの形 ys[f"x + {num}"] = y print(ys) # {'x + 0': array([0, 1, 2, 3, 4]), 'x + 1': array([1, 2, 3, 4, 5]), 'x + 2': array([2, 3, 4, 5, 6]), 'x + 3': array([3, 4, 5, 6, 7]), 'x + 4': array([4, 5, 6, 7, 8])} # 配列の要素にプロット内容を格納 plot = [] colors = ('red', 'blue', 'green', 'orange', 'black') for num, (name, y) in enumerate(ys.items()): d = go.Scatter( x=x, y=y, name=name, marker_color=colors[num], # プロット線の色 showlegend=True # 凡例を常に表示 ) plot.append(d) # 全プロット表示用のボタン作成 button_all = dict( label='all', # ボタンのラベル method='update', # ボタンの適用範囲はデータプロットとレイアウト args=[ dict(visible=[True, True]), # y1, y2の両方を表示 dict(title='all plots'), # グラフタイトル ] ) # 全プロット表示用のボタンを先に入れる buttons = [button_all] # forを使ってボタン作成を短く書く for num, data in enumerate(plot): # 一旦全てのプロットを非表示にしてから、該当するプロットを表示変更 visible = [False] * len(plot) visible[num] = [True] # ボタン作成 button = dict( label=data['name'], # ボタンのラベル method='update', # ボタンの適用範囲はデータプロットとレイアウト args=[ dict(visible=visible), # y1のみ表示 dict(title=f"y = {data['name']}"), # グラフタイトル ] ) buttons.append(button) # レイアウトに設置するためのupdatemenus作成 updatemenus = [ dict( active=0, # 初期グラフで見た目上、押されるボタン type='buttons', # ボタンのタイプはボタンに direction='right', # ボタンは右向きに配置 x=0.5, y=1.01, # ボタンの位置 xanchor='center', yanchor='bottom', # ボタンの位置の基準 buttons=buttons, # ここに設定したボタン情報を入れる ) ] # レイアウトの作成 layout = go.Layout( title='title', # グラフタイトル font_size=20, # グラフ全体のフォントサイズ hoverlabel_font_size=20, # ホバーのフォントサイズ xaxis_range=(-1, 5), # 横軸の表示範囲 yaxis_range=(-1, 9), # 縦軸の表示範囲 legend=dict(x=1, xanchor='right'), # 凡例のx位置をプロット領域の右端に updatemenus=updatemenus, # ボタンを設置 ) # グラフの表示 fig = go.Figure(data=plot, layout=layout) fig.show() # グラフの保存 prefix = 'plotly-buttons' save_name = f"{prefix}_5data" pio.orca.config.executable = '/Applications/orca.app/Contents/MacOS/orca' pio.write_html(fig, f"{save_name}.html") pio.write_image(fig, f"{save_name}.png")
複数プロットを同時に表示・非表示に
これまでは1プロットずつボタンで操作していた。しかし、複数プロットを同時に操作したい時もあるだろう。そんな時はvisible
でTrue
の箇所を増やしたらいい。
上のグラフではbutton1
がx + 0
, x + 1
、button2
がx + 2
, x + 3
、button3
がx+4
の表示に対応している。
今回は変数visibles
で各プロットの表示・非表示を決めている。このvisible
をdict
で作成することで、for
使用時にlabel
とvisible
を同時に回せる。
import numpy as np import plotly.graph_objects as go import plotly.io as pio x = np.arange(5) ys = {} for num in range(5): # np.random.seed(num) # y = np.random.rand(10) y = x + num # y = ax + bの形 ys[f"x + {num}"] = y print(ys) # {'x + 0': array([0, 1, 2, 3, 4]), 'x + 1': array([1, 2, 3, 4, 5]), 'x + 2': array([2, 3, 4, 5, 6]), 'x + 3': array([3, 4, 5, 6, 7]), 'x + 4': array([4, 5, 6, 7, 8])} # 配列の要素にプロット内容を格納 plot = [] colors = ('red', 'blue', 'green', 'orange', 'black') for num, (name, y) in enumerate(ys.items()): d = go.Scatter( x=x, y=y, name=name, marker_color=colors[num], # プロット線の色 showlegend=True # 凡例を常に表示 ) plot.append(d) # 全プロット表示用のボタン作成 button_all = dict( label='all', # ボタンのラベル method='update', # ボタンの適用範囲はデータプロットとレイアウト args=[ dict(visible=[True, True]), # y1, y2の両方を表示 dict(title='all plots'), # グラフタイトル ] ) # 全プロット表示用のボタンを先に入れる buttons = [button_all] # 該当するプロットの位置をTrueにすると表示になる visibles = dict( button1=[True, True, False, False, False], # x+0, x+1 button2=[False, False, True, True, False], # x+2, X+3 button3=[False, False, False, False, True] # x+4 ) # visiblesをforで回す for label, visible in visibles.items(): # ボタン作成 button = dict( label=label, # ボタンのラベル method='update', # ボタンの適用範囲はデータプロットとレイアウト args=[ dict(visible=visible), # y1のみ表示 dict(title=label), # グラフタイトル ] ) buttons.append(button) # レイアウトに設置するためのupdatemenus作成 updatemenus = [ dict( active=0, # 初期グラフで見た目上、押されるボタン type='buttons', # ボタンのタイプはボタンに direction='right', # ボタンは右向きに配置 x=0.5, y=1.01, # ボタンの位置 xanchor='center', yanchor='bottom', # ボタンの位置の基準 buttons=buttons, # ここに設定したボタン情報を入れる ) ] # レイアウトの作成 layout = go.Layout( title='title', # グラフタイトル font_size=20, # グラフ全体のフォントサイズ hoverlabel_font_size=20, # ホバーのフォントサイズ xaxis_range=(-1, 5), # 横軸の表示範囲 yaxis_range=(-1, 9), # 縦軸の表示範囲 legend=dict(x=1, xanchor='right'), # 凡例のx位置をプロット領域の右端に updatemenus=updatemenus, # ボタンを設置 ) # グラフの表示 fig = go.Figure(data=plot, layout=layout) fig.show() # グラフの保存 prefix = 'plotly-buttons' save_name = f"{prefix}_5data_multiple" pio.orca.config.executable = '/Applications/orca.app/Contents/MacOS/orca' pio.write_html(fig, f"{save_name}.html") pio.write_image(fig, f"{save_name}.png")
ボタンでプロットの透明度を変更
最後は応用として、ボタンを押すと対象のプロット以外のプロットが薄くなるグラフを作成。グラフの条件は以下。
all
ボタンでは、プロットの色を元の色にする- 各プロットのボタンでは、該当プロットの不透明度以外を0.1にする
上のグラフを作成するためのコートは以下。次より重要そうな部分を解説する。
import numpy as np import plotly.graph_objects as go import plotly.io as pio import webcolors # ボタンを押すとプロットの不透明度が変わるグラフ # redを(R, G, B)に変換 red = webcolors.name_to_rgb('red') print(red) # IntegerRGB(red=255, green=0, blue=0) print(tuple(red)) # (255, 0, 0) x = np.arange(5) ys = {} for num in range(5): # np.random.seed(num) # y = np.random.rand(10) y = x + num # y = ax + bの形 ys[f"x + {num}"] = y print(ys) # {'x + 0': array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]), 'x + 1': array([ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]), 'x + 2': array([ 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]), 'x + 3': array([ 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]), 'x + 4': array([ 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]), 'x + 5': array([ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]), 'x + 6': array([ 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]), 'x + 7': array([ 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]), 'x + 8': array([ 8, 9, 10, 11, 12, 13, 14, 15, 16, 17]), 'x + 9': array([ 9, 10, 11, 12, 13, 14, 15, 16, 17, 18])} # 配列の要素にプロット内容を格納 plot = [] colors = ('red', 'blue', 'green', 'orange', 'black') for num, (name, y) in enumerate(ys.items()): d = go.Scatter( x=x, y=y, name=name, marker_color=colors[num], # プロット線の色 showlegend=True # 凡例を常に表示 ) plot.append(d) # 全プロット表示用のボタン作成 color_lst = [] # 各プロットを1つずつ調べる for num, data in enumerate(plot): # 各プロットの色を抽出 color = data['marker']['color'] color_lst.append(color) button_all = dict( label='all', # ボタンのラベル method='update', # ボタンの適用範囲はデータプロットとレイアウト args=[ {'marker.color': color_lst}, # プロットの色を変更 dict(title='all plots'), # グラフタイトル ] ) # 全プロット表示用のボタンを先に入れる buttons = [button_all] # forを使ってボタン作成を短く書く for num, data in enumerate(plot): color_lst = [] alphas = [0.1] * len(plot) # 一旦全てのプロットの不透明度を0.1にする alphas[num] = 1 # 該当するプロットの不透明度を1にする # 各プロットを1つずつ調べる for num_, data_ in enumerate(plot): # 各プロットの色を抽出 color = data_['marker']['color'] # 色の名称を(R, G, B)の形式に変換 rgb = tuple(webcolors.name_to_rgb(color)) # 末尾に不透明度をつけて(R, G, B, a)形式に rgba = rgb + (alphas[num_],) color = f"rgba{rgba}" # 先頭に文字列rgnaをつけrgba(R, G, B, a)形式に color_lst.append(color) # ボタン作成 button = dict( label=data['name'], # ボタンのラベル method='update', # ボタ ンの適用範囲はデータプロットとレイアウト args=[ {'marker.color': color_lst}, # プロットの色を変更 dict(title=f"y = {data['name']}"), # グラフタイトル ] ) buttons.append(button) # レイアウトに設置するためのupdatemenus作成 updatemenus = [ dict( active=0, # 初期グラフで見た目上、押されるボタン type='buttons', # ボタンのタイプはボタンに direction='right', # ボタンは右向きに配置 x=0.5, y=1.01, # ボタンの位置 xanchor='center', yanchor='bottom', # ボタンの位置の基準 buttons=buttons, # ここに設定したボタン情報を入れる ) ] # レイアウトの作成 layout = go.Layout( title='title', # グラフタイトル font_size=20, # グラフ全体のフォントサイズ hoverlabel_font_size=20, # ホバーのフォントサイズ xaxis_range=(-1, 5), # 横軸の表示範囲 yaxis_range=(-1, 9), # 縦軸の表示範囲 legend=dict(x=1, xanchor='right'), # 凡例のx位置をプロット領域の右端に updatemenus=updatemenus, # ボタンを設置 ) # グラフの表示 fig = go.Figure(data=plot, layout=layout) fig.show() # グラフの保存 prefix = 'plotly-buttons' save_name = f"{prefix}_5data_alpha" pio.orca.config.executable = '/Applications/orca.app/Contents/MacOS/orca' pio.write_html(fig, f"{save_name}.html") pio.write_image(fig, f"{save_name}.png")
色指定のdict
は{}
で指定
all
ボタンではgo.Scatter
で作成した色を使用。色はred
などWebカラー(CSSカラー)で指定しているので、不透明度は1となる。要するに全プロットを濃くする。
色を変更するにはplot
の各データdata
においてdata[’marekr’][’color’]
で指定可能。また、ボタンでマーカーの色を指定する際にはdict
を{}
で括った方法じゃないといけない。以下のように指定するとエラーとなる。
dict(marker.color=color_lst), ^^^^^^^^^^^^^ SyntaxError: expression cannot contain assignment, perhaps you meant "=="?
webcolor
でCSSカラーをRGBへ
一方で、各ボタンでは一旦、全プロットの不透明度を0.1に変更、そのあとボタンに該当するプロットの不透明度を1に戻す。
なお、red
などのCSSカラーでは不透明度を変更することができない。したがって、色をRGBに変換できるライブラリwevcolor
を使用する。これでred→(255, 0, 0)と変換可能。
これに不透明度を最後にくっつけ(255, 0, 0, 0.1)とする。ただ、これだけだとうまく色が反映されない。実は文頭にrgba
という文字をつけないといけない。つけると完成。
# forを使ってボタン作成を短く書く for num, data in enumerate(plot): color_lst = [] alphas = [0.1] * len(plot) # 一旦全てのプロットの不透明度を0.1にする alphas[num] = 1 # 該当するプロットの不透明度を1にする # 各プロットを1つずつ調べる for num, data in enumerate(plot): # 各プロットの色を抽出 color = data['marker']['color'] # 色の名称を(R, G, B)の形式に変換 rgb = tuple(webcolors.name_to_rgb(color)) # 末尾に不透明度をつけて(R, G, B, a)形式に rgba = rgb + (alphas[num],) color = f"rgba{rgba}" # 先頭に文字列rgnaをつけrgba(R, G, B, a)形式に color_lst.append(color)
あとは今までと同じようにボタンを作成してupdatemenus
を設定したらいい。
ボタンで切り替え自由
ということで、今回はplotly
のupdatemenus
を使用してグラフにボタンを追加する方法を解説した。
同様のグラフを作成する際にボタンで切り替えられるようにしたらhtmlファイルで切り替えられるから後からも便利。
しかも、以下の記事で書いたようにplt
でhtml形式で保存するよりもplotly
のhtmlの方が自由度が高いし便利。
-
-
【plt&mpld3】pltで作ったグラフを後から編集できるようにhtmlで保存
続きを見る
なのでplotly
のボタンを活用できるようにして色々なグラフを作成していただければ幸いだ。
なお、ボタンをもう一度押した時の挙動を指定することも可能。これについては以下の記事で書いているので参照してほしい。
-
-
【plotly&ボタン】plotlyのupdatemenusに2回押し対応のbuttonsを追加
続きを見る
関連記事
-
-
【plotly&ボタン】グラフに複数種のボタンを追加
続きを見る
-
-
【plotly&buttons】ボタンを押すとプロット・背景の色が変わる変なグラフ
続きを見る
-
-
【plotly&スライダー】plotlyのslidersにスライダーを追加
続きを見る
-
-
【plotly&config】グラフのツールバーを編集する
続きを見る
-
-
【plotly&fill】goで領域を塗りつぶし
続きを見る
-
-
【plotly&バブルチャート】plotlyで各国の収入と平均寿命をバブルチャートで描く
続きを見る
-
-
【plotly&棒グラフ】go.Barでバーチャートを作成
続きを見る
-
-
【plotly&rangeslider/rangeselector】レンジスライダーとレンジセレクターで時系列を見やすく
続きを見る