plotly ボタン付きグラフの作成

# やりたいこと
- グラフ内にボタンを作成して、ボタンを押すことでプロットの表示/非表示を操作する
- ボタンを押した時にグラフタイトル、y軸ラベルなども変更する

# 環境
- Mac OS
- python 3.8.5
- plotly 4.12.0

# pip
```terminal:
pip install plotly
pip install numpy
```

# サンプルグラフ

3つのボタンで1~3次式の切り替え、タイトル、y軸ラベルの変更
<p class="codepen" data-height="265" data-theme-id="light" data-default-tab="html,result" data-user="shunta-m" data-slug-hash="XWKyOEN" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="plotly_button">
  <span>See the Pen <a href="https://codepen.io/shunta-m/pen/XWKyOEN">
  plotly_button</a> by shunta-m (<a href="https://codepen.io/shunta-m">@shunta-m</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>


```python:
import numpy as np
import plotly.offline as offline
import plotly.graph_objs as go

x = np.linspace(-5, 5, 11)
y1 = x
y2 = x ** 2
y3 = x ** 3

trace1 = go.Scatter(
    x=x,
    y=y1,
    name="y1",
    mode="lines",
    line=dict(color="red"),
    visible=False,
    showlegend=True
)

trace2 = go.Scatter(
    x=x,
    y=y2,
    name="y2",
    mode="lines",
    line=dict(color="green"),
    visible=False,
    showlegend=True
)

trace3 = go.Scatter(
    x=x,
    y=y3,
    name="y3",
    mode="lines",
    line=dict(color="blue"),
    visible=False,
    showlegend=True
)

data = [trace1, trace2, trace3]
# 初期状態としてdataの0番目(trace1)を見えるようにする
data[0].visible = True

"""
キーの説明

active: 初期状態で押されているボタンを指定、buttonsキー値のリストインデックスを入力
x: x座標、グラフ内(水色の部分)の左端が0, 右端が1, default=-0.05
xanchor: x座標をボタンのどこ(右端、左端など)に合わせるか, ("auto" | "left" | "center" | "right"), default="right"
y: x座標、グラフ内(水色の部分)の下端が0, 上端が1, default=1
yanchor:y座標をボタンのどこ(下端、上端など)に合わせるか, ( "auto" | "top" | "middle" | "bottom" ), default="top"
direction: ボタンを並べる向き, ( "left" | "right" | "up" | "down" ), default="down"
type: ドロップダウンかボタンか ( "dropdown" | "buttons" ), default="dropdown"
buttons: ボタンの設定
"""
updatemenus = [dict(active=0, x=-0.05, xanchor="right", y=1, yanchor="top", direction="up", type="buttons", buttons=[
    dict(label=trace1.name,
         method="update",
         args=[dict(visible=[True, False, False]),
               dict(title="button_plotly_{}".format(trace1.name),
                    yaxis=dict(title="yaxis_{}".format(trace1.name), showspikes=True))]),

    dict(label=trace2.name,
         method="update",
         args=[dict(visible=[False, True, False]),
               dict(title="button_plotly_{}".format(trace2.name),
                    yaxis=dict(title="yaxis_{}".format(trace2.name), showspikes=True), )]),

    dict(label=trace3.name,
         method="update",
         args=[dict(visible=[False, False, True]),
               dict(title="button_plotly_{}".format(trace3.name),
                    yaxis=dict(title="yaxis_{}".format(trace3.name), showspikes=True))]),
])]

layout = go.Layout(
    title="button_plotly_y1",
    xaxis=dict(title="xaxis", showspikes=True, domain=[0.05, 1.0]),
    yaxis=dict(title="yaxis_y1", showspikes=True),
    font=dict(size=16),
    legend=dict(orientation="h", yanchor="bottom", y=1.02, xanchor="right", x=1),
    newshape=dict(line_color='#00ffff'),
    hoverlabel=dict(font_size=20),
    autosize=True,
    updatemenus=updatemenus,
    showlegend=True,
)

fig = dict(data=data, layout=layout)

offline.plot(fig, auto_open=True, include_plotlyjs="cdn", filename=r"./button_plotly.html",
             config={'modeBarButtonsToAdd': ['drawline', 'drawopenpath', 'drawclosedpath', 'drawcircle', 'drawrect',
                                             'eraseshape']})

```

# 詳細

```python:
"""
キーの説明

active: 初期状態で押されているボタンを指定、buttonsキー値のリストインデックスを入力
x: x座標、グラフ内(水色の部分)の左端が0, 右端が1, default=-0.05
xanchor: x座標をボタンのどこ(右端、左端など)に合わせるか, ("auto" | "left" | "center" | "right"), default="right"
y: x座標、グラフ内(水色の部分)の下端が0, 上端が1, default=1
yanchor:y座標をボタンのどこ(下端、上端など)に合わせるか, ( "auto" | "top" | "middle" | "bottom" ), default="top"
direction: ボタンを並べる向き, ( "left" | "right" | "up" | "down" ), default="down"
type: ドロップダウンかボタンか ( "dropdown" | "buttons" ), default="dropdown"
buttons: ボタンの設定
"""
updatemenus = [dict(active=0, x=-0.05, xanchor="right", y=1, yanchor="top", direction="up", type="buttons", buttons=[
    dict(label=trace1.name,
         method="update",
         args=[dict(visible=[True, False, False]),
               dict(title="button_plotly_{}".format(trace1.name),
                    yaxis=dict(title="yaxis_{}".format(trace1.name), showspikes=True))]),
```

updatemenusは辞書のリスト
辞書の"buttons"キー値にボタンを作成していく

`label=trace1.name`: ボタンのラベル設定
`method="update"`: グラフの表示/非表示を変更（更新）する為
> method
Parent: layout.updatemenus[].buttons[]
Type: enumerated , one of ( "restyle" | "relayout" | "animate" | "update" | "skip" )
Default: "restyle"


`args=[dict(visible=[True, False, False]),dict(...)]`:
グラフの更新内容、１つ目のdictはプロットの表示/非表示設定
visibleの値がTrueの個所のtraceが表示される
ex) data=[trace1, trace2, trace3]なので上の場合trace1が表示、それ以外は非表示になる

２つ目のdictでその他レイアウトの更新、今回はグラフタイトルとy軸ラベルの更新

```python:
layout = go.Layout(
    title="button_plotly_y1",
    xaxis=dict(title="xaxis", showspikes=True, domain=[0.05, 1.0]),
    yaxis=dict(title="yaxis_y1", showspikes=True),
    font=dict(size=16),
    legend=dict(orientation="h", yanchor="bottom", y=1.02, xanchor="right", x=1),
    newshape=dict(line_color='#00ffff'),
    hoverlabel=dict(font_size=20),
    autosize=True,
    updatemenus=updatemenus,
    showlegend=True,
)
```

`updatemenus=updatemenus`で作成したボタンをレイアウトに追加

```python:
fig = dict(data=data, layout=layout)

offline.plot(fig, auto_open=True, include_plotlyjs="cdn", filename=r"./button_plotly.html",
             config={'modeBarButtonsToAdd': ['drawline', 'drawopenpath', 'drawclosedpath', 'drawcircle', 'drawrect',
                                             'eraseshape']})
```
fig作成、出力
`config={...}`は右上のお絵かきボタンなどを追加

# 参考サイト
公式
[Custom Buttons | Python | Plotly](https://plotly.com/python/custom-buttons/)
[layout.updatemenus | Python | Plotly](https://plotly.com/python/reference/layout/updatemenus/)

`layout.xaxis.domain`
[PlotlyのLayoutに書くdomain属性って何？ - Qiita](https://qiita.com/Mochikoko/items/6e136807024b8d6811ca)