カテゴリー

Plotly全般

【plotlyテンプレート】plotlyのグラフ作成テンプレート

2021年4月4日

テンプレート適用後のplotlyでのグラフ

こんな人にオススメ


plotlyで指定できる項目が多いから毎回毎回コードをコピペしたり新規で書いたりするのが面倒だよ!
何かテンプレートを用意して一括で管理できない?

pythonを使用してグラフを作成するには多くの方法、ライブラリが存在する。そしてその多くがmatplotlib.pyolot、通称pltを使用している。本記事ではpltとは異なったライブラリであるplotlyでグラフを作成する際に実際に使用しているグラフ作成雛形を紹介する。
python環境は以下。

  • Python 3.9.2
  • plotly 4.14.3
  • numpy 1.20.1
スポンサーリンク
スポンサーリンク

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

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

運営者メガネ

pythonでグラフを作成する

pltを使う

多くの人が使うpltでの雛形と使用前後のグラフの様子については以下の記事参照。

plt.rcParamsでデフォルトを変更した後のグラフ
【pltテンプレート】matplotlib.pyplotのグラフ作成テンプレート

続きを見る

pltはすぐに静的なグラフを作成することに長けていると思う。パッと作ってパッと確認する、このような作業には向いているように感じる。

plotlyを使う

一方でこれから紹介するplotlyは作り込むことで簡単に動的に色んなことができるグラフを作成することができる。執筆者は新型コロナウイルス感染症のおうち時間で研究に使うグラフをもっと便利にしたいと思って始めた。大体1ヶ月くらいちょこちょこ調べたら構造がわかって簡単な動的グラフも作成することができた。plotlyで作成することができる動的な動作は例えば以下。

  • 各プロット点の座標を表示
  • 見たいプロットだけ残して後のプロットを非表示にする
  • ボタンを押すとプロットや軸が変わる
  • スライダーを使用してプロットの時間経過を表示
  • htmlで保存することで後から動的なグラフを再現する

今までsubplotでグラフを並べたり複数枚のグラフを保存していたのをhtmlファイル1枚で完結することができ、さらに後から確認・編集することができるのはなかなか便利だと思う。

plotlyの構造

plotlyを使用したことがない方が多いと思うので、ここでは軽く構造を説明する。執筆者本人もまだまだ勉強中なので、不足していることや間違っていることがあるかもしれないのでそこはご了承ください。

大まかな流れ

plotlyでのグラフ作成には大きく分けて2種類の方法があると思う。

  1. 予めプロットとレイアウトの配列を作成し、その配列に必要な項目を随時アップデートする
  2. 予め必要な項目を配列に入れ、それをプロットとレイアウトの配列に入れる

すなわち最初に箱を作ってそこに中身をどんどん入れるか、最後に箱を作るのと同時に中身を入れるのかの違い。自分は後者の方に慣れているので後者の書き方に沿う。

雛形として設定している項目

レイアウト本体

執筆者の設定している項目は前節で言えばレイアウトの部分。プロットに関してはその時々にあった書き方をしたいのでデフォルトを設定していない。

設定しているレイアウトは以下。辞書型で書く必要があるので慣れていない人は慣れよう。このdefreturnをレイアウト設定時に置くことでレイアウトを一式変更することができる。

def plotly_layout():
    """plotlyのlayoutのtemplate

    Returns
    -------
    dict
        plotlyのlayoutのtemplate
        各グラフのlayout作成時に上書きすることも可能
    """

    layout_template = dict(
        layout=go.Layout(
            width=1280 * 1.5, height=720 * 1.5,
            title=dict(
                x=0., y=0.99, xanchor='left', yanchor='top',
                xref='paper', yref='container',
            ),
            xaxis=dict(
                ticks='inside', zeroline=False, linewidth=1,
                showline=True, linecolor='black', mirror='allticks',
            ),
            yaxis=dict(
                ticks='inside', zeroline=False, linewidth=1,
                showline=True, linecolor='black', mirror='allticks',
            ),
            yaxis2=dict(
                gridcolor='#d5d5d5',
                ticks='inside', zeroline=False, linewidth=1,
                showline=True, linecolor='black', mirror=False,
                overlaying='y', side='right',
            ),
            font=dict(
                family='Times New Roman',
                color='black', size=15,
            ),
            paper_bgcolor='rgba(0,0,0,0)',
            plot_bgcolor='rgba(0,0,0,0)',
            legend=dict(
                x=1, y=1, orientation='v',
                xanchor='right', yanchor='top',
                itemclick='toggleothers', itemdoubleclick='toggle',
                bgcolor='rgba(0,0,0,0)',
                bordercolor='black', borderwidth=1,
            ),
            showlegend=True,
            margin=dict(l=50),
            hoverdistance=30,
            showlegend=True,
            hovermode='closest',
        )
    )
    return layout_template

すごい量になるが一つ一つ解説していく。デフォルト値や引数の説明などはplotlyのサイトに載っている。

なお、レイアウトの中でも別途指定が必要な項目もある。これについては他の記事で書く予定。

グラフの幅と高さ

グラフの幅の高さは以下で指定する。

width=1280 * 1.3,
height=720 * 1.3,

widthがグラフ幅でheightがグラフ高さを示す。ここで気をつけないといけないのが、このグラフ幅はプロット領域も軸ラベルとかのある枠も含めたグラフ全体のサイズということ。後述するプロット用のコードでプロットの凡例の名前が長すぎるとどんどんプロット部分が縦長になってしまう。
2021年4月14日更新
widthheightを設定すると、記事中に表示したグラフが自動サイズ変更(レスポンシブ対応)しなくなるので、当面の間widthheightについては設定しません。

グラフタイトル

グラフタイトルは以下で指定する。辞書型の中の引数で内容を指定している。

title=dict(
    x=0., y=0.99, xanchor='left', yanchor='top',
    xref='paper', yref='container',
),

x, yでタイトルの位置を相対的に指定する。xanchor, yanchorx, yを計測する基準点をどこにするか。xref, yrefx, yの置く位置の基準点を決める。'paper'の場合はプロット領域、'container'の場合はグラフ全体。自分は横位置はプロット領域の左端と同じように、縦位置はグラフ全体の上端から0.01だけ下の部分がタイトルボックスの上端に一致するように設定している。

なぜ横位置を左にしているかというと、初めてグラフを作成したときに左に寄っていたから。pltと違って違和感あるなと思いつつ、それがpltplotlyのパッと見の違いを出していたからそのまま左にしている。

横軸、縦軸、第二縦軸

横軸はxaxis、縦軸はyaxis、第二縦軸はyaxis2で以下のように指定している。

xaxis=dict(
    ticks='inside', zeroline=False, linewidth=1,
    showline=True, linecolor='black', mirror='allticks',
),
yaxis=dict(
    ticks='inside', zeroline=False, linewidth=1,
    showline=True, linecolor='black', mirror='allticks',
),
yaxis2=dict(
    gridcolor='#d5d5d5',
    ticks='inside', zeroline=False, linewidth=1,
    showline=True, linecolor='black', mirror=False,
    overlaying='y', side='right',
),

それぞれの引数について以下に示す。

まずは第一軸に関する引数

  • ticks='inside':目盛線の向きを内側にする
  • zeroline=False:それぞれ該当する軸の0の値に直線を引かない
  • linewidth=1:軸の太さを1に設定
  • showline=True:軸の線自体を書く
  • linecolor='black':軸の色を黒にする
  • mirror='allticks':反対側の軸にも目盛を振る

次に第二縦軸に関する引数

  • gridcolor='#d5d5d5':グリッドの色を#d5d5d5に変更する(グリッド自体はデフォルトでON)
  • mirror=False:反対側の軸・目盛をOFFにする。しないと軸や目盛が被ってしまう
  • overlaying='y':第一軸のyに対して重ねる
  • side='right':第二縦軸は右側に配置

現状のままだと二軸グラフにした時にグリッドが重なるのを色で防いでいるが、もう二軸グラフの時はグリッドはないほうがいいかも。

フォント

フォントについては以下のように指定している。

font=dict(
    family='Times New Roman',
    color='black', size=15
),

フォントは以前のpltの記事でも言ったようにTimes New Romanを使用し、フォントサイズは大きめにしている。フォントについてのお話は以下の記事参照。

plt.rcParamsでデフォルトを変更した後のグラフ
【pltテンプレート】matplotlib.pyplotのグラフ作成テンプレート

続きを見る

グラフ背景

グラフ背景に関しては以下のように設定している。グラフの背景は無色透明。スライドに載せるときなどにグラフ重ねが楽。

paper_bgcolor='rgba(0,0,0,0)',
plot_bgcolor='rgba(0,0,0,0)',

pltと異なるのが以下の点。

  • RGBAの時は(0, 0, 0, 0)の指定ではなくrgba(0, 0, 0, 0)のように最初にrgbaとつける必要がある
  • pltの時はRGBは0から1の間で値を決めていたが、plotlyの場合は0から255になる

特に後者の色に関しては変換しないといけないので面倒。勝手に変換してくれる関数があったような気がしたがパッと出ないので出た時にでもまた記事にする。

また、paper_bgcolorだけ指定するとグラフ全体が、plot_bgcolorを指定するとpaper_bgcolorを指定していてもプロット部分の色はplot_bgcolorの色が反映される。

凡例

プロットの凡例に関しては以下のように設定している。凡例中での改行ができないので(プロット点のグループ化で擬似的にはできる)、とりあえずはグラフのレイアウトが崩れないように設定している。

legend=dict(
    x=1, y=1, orientation='v',
    xanchor='right', yanchor='top',
    itemclick='toggleothers', itemdoubleclick='toggle',
    bgcolor='rgba(0,0,0,0)', bordercolor='black', borderwidth=1,
),
showlegend=True,

legendの辞書のそれぞれの引数について新出のものだけ以下に示す。

  • orientation='v':次の凡例を下に続ける
  • itemclick='toggleothers':凡例を一回クリックした時、クリックしたプロット以外のプロットを非表示
  • itemdoubleclick='toggle':凡例をダブルクリックした時、クリックしたプロットを非表示
  • bgcolor='rgba(0,0,0,0)':凡例のボックスの背景色を無色透明にする。すでに述べたように全部0なので無色透明
  • bordercolor='black':凡例のボックスの枠の色を黒にする
  • borderwidth=1:凡例のボックスの枠の線の太さを1にする

showlegendについては、デフォルトで凡例が出ないようになっていたので明示的にTrueにしている。

余白

margin=dict(l=50),

デフォルトは80でやたらと右寄りの印象があったので左の余白を減らした。減らしすぎると縦軸と縦軸ラベルが重なるので注意。

ホバーを判定する距離

plotlyにはプロット点付近にマウスカーソルを近づけるとその値が表示されるという機能が備わっている。このホバーを認識するための距離として以下のように設定している。

hoverdistance=30,

デフォルトが20で執筆者の指定が30。実は結構動作が変わっていて試しに300とかにするとどこにマウス持っていってもどこかしらのプロット点に反応するレベルになる。

凡例は常に表示

showlegend=True,

2021年5月7日更新。

プロットの凡例が表示されないことがあるので凡例を表示するように明示。

マウスオーバーは1プロットのみ

hovermode='closest',

2021年5月7日更新。

マウスオーバーした時に複数プロットの情報を見ることができるようにすると見にくいので、デフォルトでは1プロットの情報だけ表示。右上のツールバーで変更可能。

実際にグラフ化

ここでは実際に上記のテンプレートを使用する前後でグラフがどう変わるのかを示す。本記事で書くと長くなるので、今回はグラフをプロットする時の細かいコードや保存時の注意については触れない。また他の記事で書く予定。

今回使用するコードは以下。

import plotly
import plotly.graph_objects as go
import plotly.io as pio
import numpy as np


def plotly_layout():
    """plotlyのlayoutのtemplate

    Returns
    -------
    dict
        plotlyのlayoutのtemplate
        各グラフのlayout作成時に上書きすることも可能
    """

    layout_template = dict(
        layout=go.Layout(
            # width=1280 * 1.5, height=720 * 1.5,
            title=dict(
                x=0., y=0.99, xanchor='left', yanchor='top',
                xref='paper', yref='container',
            ),
            xaxis=dict(
                ticks='inside', zeroline=False, linewidth=1,
                showline=True, linecolor='black', mirror='allticks',
            ),
            yaxis=dict(
                ticks='inside', zeroline=False, linewidth=1,
                showline=True, linecolor='black', mirror='allticks',
            ),
            yaxis2=dict(
                gridcolor='#d5d5d5',
                ticks='inside', zeroline=False, linewidth=1,
                showline=True, linecolor='black', mirror=False,
                overlaying='y', side='right',
            ),
            font=dict(
                family='Times New Roman',
                color='black', size=15,
            ),
            paper_bgcolor='rgba(0,0,0,0)',
            plot_bgcolor='rgba(0,0,0,0)',
            legend=dict(
                x=1, y=1, orientation='v',
                xanchor='right', yanchor='top',
                itemclick='toggleothers', itemdoubleclick='toggle',
                bgcolor='rgba(0,0,0,0)',
                bordercolor='black', borderwidth=1,
            ),
            showlegend=True,
            margin=dict(l=50),
            hoverdistance=30,
        )
    )
    return layout_template


def graph(name, template=None):
    """2次関数をグラフ化

    Parameters
    ----------
    name : str
        作成したグラフの保存名
    template : dict or NoneType, optional
        レイアウトのテンプレートを指定, by default None
    """

    x = np.arange(-10, 10 + 1)
    y = x ** 2

    # プロットするデータを配列に入れる
    plot = []
    d = go.Scatter(
        mode='lines+markers',
        x=x,
        y=y,
        name='plot1',
        marker=dict(symbol='circle'),
        line=dict(dash='solid', color='blue'),
        hoverlabel=dict(
            font=dict(
                family='Times New Roman', size=15
            )
        ),
        hovertemplate='ホバーだよ<br>'
        + 'x=%{x}<br>'
        + 'y=%{y}<br>'
        + "<extra>ホバー2</extra>",
    )
    plot.append(d)

    # レイアウトを決める
    layout = go.Layout(
        template=template,
        title=dict(
            text='title',
        ),
        xaxis=dict(
            title='x',
        ),
        yaxis=dict(
            title='y',
        ),
    )

    # 作成したデータの入った配列と、レイアウトの配列を図にする
    fig = go.Figure(data=plot, layout=layout)
    plotly.offline.iplot(fig)

    # 作成したグラフを保存
    plotly.io.orca.config.executable = ('/Applications/orca.app/'
                                        'Contents/MacOS/orca')
    pio.write_html(
        fig,
        f"plotly-base_plotly_{name}.html", auto_open=False
    )
    pio.write_image(fig, f"plotly-base_plotly_{name}.png")


# template=Noneだとテンプレートは反映されない
graph(name='before', template=None)

# template=plotly_layout()だとテンプレートが反映される
graph(name='after', template=plotly_layout())

テンプレートを使用する前

テンプレートを使用する前、すなわちデフォルトの設定では以下のようなグラフになる。

デフォルトのplotlyでのグラフ

デフォルトのplotlyでのグラフ

plolyのグラフはデフォルトではプロット部分の色が#e6ecf5(RGB:230, 236, 245)くらいの色になっている(MacのDigital color meterで測定)。また、フォントが異常に小さい印象。
以下に実際に作成したグラフのHTMLバージョンを示す。


テンプレートを使用した後

テンプレートを使用した後、すなわちレイアウトを変更した後の設定では以下のようなグラフになる。

テンプレート適用後のplotlyでのグラフ

テンプレート適用後のplotlyでのグラフ

背景は無色透明で目盛は内側で上下左右に配置。これでもまだフォントは小さいがそれでも少しは大きくなっている。また、マウスカーソルをプロット点に近づけるとそのプロットのデータが表示されるほか、凡例をダブルクリックすることでプロット点を非表示にすることもできる。
以下に実際に作成したグラフのHTMLバージョンを示す。グラフはレスポンシブ対応しているはずなので、PCで閲覧している方はウィンドウサイズを変更してみてください。グラフのサイズが変更されるはず。


plotlyはカスタマイズが簡単にできる

今回はplotlyのレイアウトのテンプレートを紹介した。今回もpltと同様、カスタム方法は千差万別。凡例をクリックする時のラグだったり各種位置だったり色々と設定を試してみて楽しんでほしい。

これから当ブログで使用する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全般
-, , ,