カテゴリー

Plotly全般

【plotly&ボタン】plotlyのupdatemenusに2回押し対応のbuttonsを追加

2021年4月14日

こんな人にオススメ

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
スポンサーリンク
スポンサーリンク

運営者のメガネと申します。TwitterInstagramも運営中。

自己紹介はこちらから、お問い合わせはこちらからお願いいたします。

運営者メガネ

作成したコード全文

下準備(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関連。今回はシンプルな配列からできるグラフを使用するのでplotlygoだけ。あとはグラフ保存用のpio.

goで散布図を作成する方法、orcaplotlyのグラフを保存する方法については以下。

【plotly&go.Scatter】plotlyの散布図グラフの描き方

続きを見る

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回押すと全プロットが非表示になり、再度押すと全プロットが表示されるということ。

  1. args(1回目): 全プロットを非表示
  2. args2(2回目): 全プロットを表示

ただ、気をつけないといけない点がある。それが変数updatemenusの引数active。これを-1にしておかないと初めからボタンが1回押された状態で初期グラフが作成される。

なので、1回目のボタン押下がargs2の処理となり、再度押した時が実質3回目の処理=1回目の処理となる。なので作成する際には注意が必要。

残りの部分については復習で作成したグラフと大差ない。visibleTrueだと表示で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のマーカーのシンボル

続きを見る

【plotly&config】グラフのツールバーを編集する

続きを見る

【plotly&ボタン】plotlyのupdatemenusにbuttonsを追加

続きを見る

【plotly&スライダー】plotlyのslidersにスライダーを追加

続きを見る

【plotly&Scattergl】大量のデータをplotlyで軽くグラフ化

続きを見る

plotlyでグラフを静止画として保存する際に出るポップアップ
【plotly&orca】plotlyで静止画保存(orca)

続きを見る

【plotly&table+scatter】subplotsで表と散布図を同時にグラフ化

続きを見る

【plotly&ボタン】グラフに複数種のボタンを追加

続きを見る

 

関連コンテンツ

スポンサーリンク

Amazonのお買い物で損したない人へ

1回のチャージ金額通常会員プライム会員
¥90,000〜2.0%2.5%
¥40,000〜1.5%2.0%
¥20,000〜1.0%1.5%
¥5,000〜0.5%1.0%

Amazonギフト券にチャージすることでお得にお買い物できる。通常のAmazon会員なら最大2.0%、プライム会員なら2.5%還元なのでバカにならない。

ゲットしたポイントは通常のAmazonでのお買い物に使えるからお得だ。一度チャージしてしまえば、好きなタイミングでお買いものできる。

なお、有効期限は10年だから安心だ。いつでも気軽にAmazonでお買い物できる。

Amazonチャージはここから出来るで

もっとお得なAmazon Prime会員はこちらから

30日間無料登録

執筆者も便利に使わせてもらってる

スポンサーリンク

  • この記事を書いた人

メガネ

独学でpythonを学び天文学系の大学院を修了。 ガジェット好きでMac×Android使い。色んなスマホやイヤホンを購入したいけどお金がなさすぎて困窮中。 元々、人見知りで根暗だったけど、人生楽しもうと思って良い方向に狂ったために今も人生めちゃくちゃ楽しい。 pythonとガジェットをメインにブログを書いていますので、興味を持たれましたらちょこちょこ訪問してくだされば幸いです🥰。 自己紹介→変わって楽しいの繰り返し

-Plotly全般
-, , ,