こんな人にオススメ
plotly
でボタンを追加して動作を割り当てることはできたけど、もう一回押した時に何か動作を割り当てることってできる?
できるならボタンの数が減ってよりスタイリッシュになるのに...
ということで、今回はplotly
のボタン(updatemenus
)でボタンを連続して2回押した時に、動作を割り当てる方法について解説する。以下のボタン追加の方法がわかっていれば簡単。
-
-
【plotly&ボタン】plotlyのupdatemenusに2回押し対応のbuttonsを追加
続きを見る
1引数コードを追加するだけで2回目のボタンの設定が可能。もう一回のボタンを作ることで、ボタンでの動作を元に戻したり追加の動作を設定可能。
基本的なボタンの作成方法とか考え方は上の記事を参照、本記事ではargs2を使った2回目のボタン作成方法とちょっとしたボタンの応用方法について解説する。
python環境は以下。
- Python 3.10.1
- plotly 5.4.0
- plotly-orca 3.4.2
なお、新しく立ち上げたサイト「Pro天パ」ではリライト(書き直し)した記事を公開している。併せてご覧いただきたい。
作成したコード全文
下準備(import)
import sys import numpy as np import matplotlib.cm as cm import plotly import plotly.graph_objects as go import plotly.io as pio sys.path.append('../../') import plotly_layout_template as template
まずは下準備としてのimport
関連。今回はシンプルな配列からできるグラフを使用するのでplotly
のgo
だけ。あとはグラフ保存用のpio
.
go
で散布図を作成する方法、orca
でplotly
のグラフを保存する方法については以下。
-
-
【plotly&go.Scatter】plotlyの散布図グラフの描き方
続きを見る
-
-
【plotly&orca】plotlyで静止画保存(orca)
続きを見る
(復習)グラフにボタンを追加する
まずはシンプルにグラフにボタンを作成する方法について復習する。1ボタンごとにdict
で作成し、全ボタンを一括でlist
に入れて用意する。
それをグラフのどの位置に設置するのかなどを指定してから、go.Layout
の引数updatemenus
に入れることでボタンを作成できた。
ここでのグラフは全プロットを表示するallボタン、y1
だけ表示するy1
ボタン、そしてy2
だけ表示するy2
ボタンの合計3ボタンを作成。
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-args2' 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")
args2
で2回押した時のボタン操作を割り当て
ということで、本題のボタンを2回押した時のグラフを作成。と言っても作成方法はシンプルで、argsを使った階層と同じ階層に引数args2を入れたらいい。
具体的には以下。visibleなどの構造もargs2と全く同じでいい。内容は変えないと意味がないけど、作り方は同じ。
# args2を適用し全プロット表示と全プロット非表示のボタンを追加 button_all = dict( label='all or nothing', # ボタンのラベル method='update', # ボタンの適用範囲はデータプロットとレイアウト # aegsを1回押した時のボタンの挙動 args=[ dict(visible=[False, False]), # y1, y2の両方を表示 dict(title='No plots'), # グラフタイトル ], # aegs2がもう一回押した時のボタンの挙動 args2=[ dict(visible=[True, True]), # y1, y2の両方を表示 dict(title='all plots'), # グラフタイトル ] )
ここで作成したボタンは以下の2種類。要するに1回押すと全プロットが非表示になり、再度押すと全プロットが表示されるということ。
args
(1回目): 全プロットを非表示args2
(2回目): 全プロットを表示
ただ、気をつけないといけない点がある。それが変数updatemenus
の引数active
。これを-1にしておかないと初めからボタンが1回押された状態で初期グラフが作成される。
なので、1回目のボタン押下がargs2
の処理となり、再度押した時が実質3回目の処理=1回目の処理となる。なので作成する際には注意が必要。
残りの部分については復習で作成したグラフと大差ない。visible
がTrue
だと表示でFalse
だと非表示。そしてtitle
でグラフタイトルを変更している。
import plotly.graph_objects as go import plotly.io as pio # 2つのプロットを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'), ] # args2を適用し全プロット表示と全プロット非表示のボタンを追加 button_all = dict( label='all or nothing', # ボタンのラベル method='update', # ボタンの適用範囲はデータプロットとレイアウト # aegsを1回押した時のボタンの挙動 args=[ dict(visible=[False, False]), # y1, y2の両方を表示 dict(title='No plots'), # グラフタイトル ], # aegs2がもう一回押した時のボタンの挙動 args2=[ dict(visible=[True, True]), # y1, y2の両方を表示 dict(title='all plots'), # グラフタイトル ] ) # ボタンをlistにまとめる buttons = [button_all] # レイアウトに設置するためのupdatemenus作成 updatemenus = [ dict( # active=0にしていると、args2のボタンが1回目の処理扱いになる active=-1, # 初期グラフで見た目上、推されるボタン 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-args2' save_name = f"{prefix}_double_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")
args3
はない
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'), ] # args3はない button_all = dict( label='all or nothing', # ボタンのラベル method='update', # ボタンの適用範囲はデータプロットとレイアウト # aegsを1回押した時のボタンの挙動 args=[ dict(visible=[True, True]), # y1, y2の両方を表示 dict(title='all plots'), # グラフタイトル ], # aegs2がもう一回押した時のボタンの挙動 args2=[ dict(visible=[False, False]), # y1, y2の両方を表示 dict(title='No plots'), # グラフタイトル ], # aegs2がもう一回押した時のボタンの挙動 args3=[ dict(visible=[True, False]), # y1, y2の両方を表示 dict(title='1 plots'), # グラフタイトル ] )
args2
があるならargs3
があるのかというと実はそうではない。args3
を指定すると以下のようにエラーが出る。あくまでもargs
は2まで。
シンボルサイズや線の種類を変更したボタンを作成
最後にちょっとした応用として以下の機能を持つボタンを作成。
- シンボルサイズを変更
- 線の種類を変更
- 線の太さ、マーカーの種類とサイズを変更
最終的なコードは以下。次より各ボタンについて解説する。
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'), ] # args2を適用しマーカーのシンボルのサイズを変更するボタンを作成 button_size = dict( label='symbol size', # ボタンのラベル method='update', # ボタンの適用範囲はデータプロットとレイアウト # aegsを1回押した時のボタンの挙動 args=[ {'marker.size': 30}, # プロットのマーカーのサイズを変更 dict(title='symbol size: 30'), # グラフタイトル ], # aegs2がもう一回押した時のボタンの挙動 args2=[ {'marker.size': 6}, # プロットのマーカーのサイズをデフォルトに dict(title='symbol size: 6'), # グラフタイトル ] ) # args2を適用し線の種類を変更するボタンを作成 button_dash = dict( label='line dash', # ボタンのラベル method='update', # ボタンの適用範囲はデータプロットとレイアウト # aegsを1回押した時のボタンの挙動 args=[ {'line.dash': 'dash'}, # プロット線の種類を破線に dict(title='line dash: dash'), # グラフタイトル ], # aegs2がもう一回押した時のボタンの挙動 args2=[ {'line.dash': 'solid'}, # プロット線の種類を実線に dict(title='line dash: solid'), # グラフタイトル ] ) # args2を適用し線の太さ・マーカーの種類とサイズを変更するボタンを作成 button_width_symbol = dict( label='line width & symbol', # ボタンのラベル method='update', # ボタンの適用範囲はデータプロットとレイアウト # aegsを1回押した時のボタンの挙動 args=[ { 'line.width': 0.5, # 線の太さ 'marker.symbol': 'star', # マーカーの種類 'marker.size': 10 # マーカーのサイズ }, # グラフタイトルと横軸ラベル dict(title='line width: 0.5', xaxis=dict(title='X (1st button)')), ], # aegs2がもう一回押した時のボタンの挙動 args2=[ { 'line.width': 2, # 線の太さ 'marker.symbol': 'square', # マーカーの種類 'marker.size': 10 # マーカーのサイズ }, # グラフタイトルと縦軸ラベル dict(title='line width: 2', yaxis=dict(title='Y (2nd button)')), ] ) # ボタンをlistにまとめる buttons = [button_size, button_dash, button_width_symbol] # レイアウトに設置するためのupdatemenus作成 updatemenus = [ dict( # active=0にしていると、args2のボタンが1回目の処理扱いになる active=-1, # 初期グラフで見た目上、推されるボタン 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-args2' save_name = f"{prefix}_double_buttons_ex" 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")
マーカーサイズを変更
# args2を適用しマーカーのシンボルのサイズを変更するボタンを作成 button_size = dict( label='symbol size', # ボタンのラベル method='update', # ボタンの適用範囲はデータプロットとレイアウト # aegsを1回押した時のボタンの挙動 args=[ {'marker.size': 30}, # プロットのマーカーのサイズを変更 dict(title='symbol size: 30'), # グラフタイトル ], # aegs2がもう一回押した時のボタンの挙動 args2=[ {'marker.size': 6}, # プロットのマーカーのサイズをデフォルトに dict(title='symbol size: 6'), # グラフタイトル ] )
go.Scatter
のマーカーサイズを変更するにはgo.Scatter
の引数marker
の引数size
を変更する必要がある。なのでargs
, args2
でアクセスする必要がある。
しかし、dict(marker_size=30)
のように指定しても反映されないので、{'marker.size': 30}
のように書く必要がある。
線の種類を変更
# args2を適用し線の種類を変更するボタンを作成 button_dash = dict( label='line dash', # ボタンのラベル method='update', # ボタンの適用範囲はデータプロットとレイアウト # aegsを1回押した時のボタンの挙動 args=[ {'line.dash': 'dash'}, # プロット線の種類を破線に dict(title='line dash: dash'), # グラフタイトル ], # aegs2がもう一回押した時のボタンの挙動 args2=[ {'line.dash': 'solid'}, # プロット線の種類を実線に dict(title='line dash: solid'), # グラフタイトル ] )
線の種類を変更する際も考え方は同じ。線の種類はgo.Scatter
の引数line
の引数dash
で変更可能。{'line.dash': 'dash'}
が破線で{'line.dash': 'solid'}
が実線に対応する。
その他にもdot
(点線)やdashdot
(一点鎖線)などがある。詳しくは以下参照。
-
-
【plotly&size, width】Scatterのサイズやlineの太さ一覧表を作成
続きを見る
線の太さ、マーカーの種類とサイズを変更
# args2を適用し線の太さ・マーカーの種類とサイズを変更するボタンを作成 button_width_symbol = dict( label='line width & symbol', # ボタンのラベル method='update', # ボタンの適用範囲はデータプロットとレイアウト # aegsを1回押した時のボタンの挙動 args=[ { 'line.width': 0.5, # 線の太さ 'marker.symbol': 'star', # マーカーの種類 'marker.size': 15 # マーカーのサイズ }, # グラフタイトルと横軸ラベル dict(title='line width: 0.5', xaxis=dict(title='X (1st button)')), ], # aegs2がもう一回押した時のボタンの挙動 args2=[ { 'line.width': 2, # 線の太さ 'marker.symbol': 'square', # マーカーの種類 'marker.size': 10 # マーカーのサイズ }, # グラフタイトルと縦軸ラベル dict(title='line width: 2', yaxis=dict(title='Y (2nd button)')), ] )
最後は複数の変更を適用する方法。線の太さはline.width
、マーカーの種類はmarker.symbol
、そしてマーカーのサイズはmarker.size
で変更することが可能。
また、args
, args2
の2つ目のdict
はレイアウト関連の情報を入れるんだけど、今回はプラスして横軸・縦軸のラベルも変更するように指定してみた。
これでボタンを押すと軸ラベルが追加されるようになる。
ボタンを押して変わるもの、変わらないもの
色んなボタンを押しまくると変更される箇所と変更されない箇所がある。これはボタンで指定した処理による。
というのも、line.width
は3つ目のボタン、line.dash
は2つ目のボタンでしか適用されない。なので線の太さと線の種類はこれらのボタンを押さない限り変更されない。
一方で、marker.size
は1つ目と3つ目のボタンで指定したので、ボタンを押す度に処理が行われて、内容が上書きされていく。
2回目のボタンで自由度がさらに増す
今回はploty
のボタン機能で2回ボタンを押した時に動作を設定する方法を解説した。1つの機能のボタンだけでもかなり実用的だが、そこに追加で機能を付加できるのは便利。
変更して元に戻すと言った使い方をすればボタンが1つで済むし、隠し機能として娯楽目的で作成することもできる。
plotly
はインタラクティブなライブラリなので、今回の記事をきっかけに様々なグラフを作成していただくと幸いだ。
関連記事
-
-
【plotly&go.Scatter】plotlyの散布図グラフの描き方
続きを見る
-
-
【plotly&マーカー】plotlyのマーカーのシンボル
続きを見る
-
-
【plotly&config】グラフのツールバーを編集する
続きを見る
-
-
【plotly&ボタン】plotlyのupdatemenusにbuttonsを追加
続きを見る
-
-
【plotly&スライダー】plotlyのslidersにスライダーを追加
続きを見る
-
-
【plotly&Scattergl】大量のデータをplotlyで軽くグラフ化
続きを見る
-
-
【plotly&orca】plotlyで静止画保存(orca)
続きを見る
-
-
【plotly&table+scatter】subplotsで表と散布図を同時にグラフ化
続きを見る
-
-
【plotly&ボタン】グラフに複数種のボタンを追加
続きを見る