カテゴリー

Plotly全般

【plotly&kwargs】グラフ作成時の設定を後から追加できるように

2021年9月10日

こんな人にオススメ

plotlyでグラフを描くときに関数を使用するけど、設定したい引数が多すぎて関数を定義するときに長くなっちゃう。

かといって引数を使用しないと関数としての魅力が激減してしまう。どうしたらいい?

ということで、今回は関数を使用してplotlyのグラフを描く際に便利な、関数と可変長引数kwargsについて解説する。kwargsをうまく活用することで、関数自体がスッキリするし、後から自由に引数を追加することも。

突然アイデアが降ってきた今回の記事のkwargs、これから多用しそうなくらい便利だった。知っていた人からしたら当たり前だし、簡単に思いつきそうな内容だけど、知るのと知らないのでは雲泥の差。執筆者は進化した(大袈裟)、

python環境は以下。

  • Python 3.9.6
  • plotly 5.1.0
  • plotly-orca 3.4.2

運営者のメガネです。YouTubeTwitterInstagramも運営してます。

自己紹介はこちらから、お問い合わせはこちら。

運営者メガネ

作成したコード全文

下準備

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

# 使用するデータ
x = (0, 1, 2, 3, 4)
y = (20, 15, 10, 25, 28)

まずは下準備としてのimport関連。今回はplotlyの自作テンプレートを使用せず、デフォルトのグラフを描くことにする。テンプレートを使用することで、簡単にキレイなグラフを作成することが可能になる。

【随時更新 備忘録】plotlyのグラフ即席作成コード

こんな人にオススメ plotlyって{ ...

続きを見る

また、使用するデータは適当に作成した5データ。初めはシンプルに直線にしようと思ったけど、俺曲がっている方がマーカーがわかりやすかったので折ってやった。

グラフ保存用の関数

# グラフ保存用の関数
def save(fig, config, save_name):
    pio.orca.config.executable = '/Applications/orca.app/Contents/MacOS/orca'
    pio.write_html(fig, f"{save_name}.html", config=config,)
    pio.write_image(fig, f"{save_name}.png")

グラフ共通事項として、作成したグラフを保存するための関数を作成。保存形式はhtmlとpng。関数ではconfigを引数としているが、本記事では全てconfig=Noneとして初期configのまま進める。

configとはグラフ上に出てくるツールバーのことで、これを使用することで、図形を追加したり全グラフのホバーを表示したりできる。

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

こんな人にオススメ plotlyでグ} ...

続きを見る

引数を設定すると便利だが、関数の引数が長くなる

まずは、kwargsを導入する以前の問題として、そもそも使わない場合にどんな問題が発生するのかということを書いていく。大きな問題でなければkwargsを使用せず今まで通り進めたらいい。

元から引数を入れると他の引数入れられない


plotlyのグラフはグリグリ動かすことができるということと、豊富なカスタムが魅力。なので、以下のコードのようにScatterの中に色々と引数を設定することで、これらの豊富な機能を付与することができる。

しかし、関数を使用する場合、go.Scatterに入れた引数を外から変更することができない。ということで、他の場所でも関数を使用することができない。一応x, y, nameは変更できるがその他はできない。

# 元から引数を入れると他の引数入れられない
def scatter_simple(x, y, name):
    d = go.Scatter(
        x=x, y=y, name=name,
        line=dict(width=3),  # プロット線の設定
        marker=dict(
            symbol='star', size=20,  # マーカーの設定
            line=dict(color='red', width=2),  # マーカーの線の設定
        ),
    )

    return d

グラフの描き方は以下のように行う。もちろん関数化してもいいけど、簡略化するために関数化していない。

name = 'simple'
plot = [scatter_simple(x=x, y=y, name=name,)]

fig = go.Figure(data=plot)
fig.show()
save(fig=fig, config=None, save_name=name)

かといって引数を設定すると長い

# 引数として設定すると引数を毎回設定しないといけないし長い
def scatter_argument(x, y, name, line_width, symbol, size,
                     marker_line_color, marker_line_width):
    d = go.Scatter(
        x=x, y=y, name=name,
        line=dict(width=line_width),
        marker=dict(
            symbol=symbol, size=size,
            line=dict(color=marker_line_color, width=marker_line_width),
        ),
    )

    return d

かといって、関数に引数を設定しすぎてしまうと引数部分が長すぎることになる。もちろん引数名を簡略化してもいいんだけど、わかりやすくするならやっぱり長くなるのかなと。

また、関数を使用する際に、引数が多いとその全てを埋めないといけないから、ここでも長くなってしまう。

name = 'argument'
plot = [
    scatter_argument(
        x=x, y=y, name=name, line_width=3, symbol='star', size=20,
        marker_line_color='red', marker_line_width=2
    ),
]

fig = go.Figure(data=plot)
fig.show()
save(fig=fig, config=None, save_name=name)

初期値を設定すると引数がハンパない

# 引数の初期値を設定すると呼び出し時には楽ができるが、関数定義の時が長い
def scatter_argument_ini(x, y, name, line_width=3, symbol='star', size=20,
                         marker_line_color='red', marker_line_width=2):
    d = go.Scatter(
        x=x, y=y, name=name,
        line=dict(width=line_width),
        marker=dict(
            symbol=symbol, size=size,
            line=dict(color=marker_line_color, width=marker_line_width),
        ),
    )

    return d

なら、初期値を設定すればいいのでは、となるがこの場合は関数の引数がさらに長くなる。引数を増やすとさらに長くなるし、次の行にもなってしまう。

一応、pythonにはPEP8という規約のようなものがあり、これに従うと改行しまくらないといけなくなる。

【PEP8&flake8】pythonにおけるPEP8とflake8

こんな人にオススメ pythonにつ{ ...

続きを見る

また、初期値を設定したので、その初期値のままでいい部分は指定しなくてもいい。以下ではsymbolmarker_line_widthだけを変更・指定を行った。

name = 'argument_ini'
# 初期値があるから、変更したい引数だけ変更すればいい
plot = [
    scatter_argument_ini(
        x=x, y=y, name=name, symbol='hexagram', marker_line_width=1
    ),
]

fig = go.Figure(data=plot)
fig.show()
save(fig=fig, config=None, save_name=name)

可変長キーワード引数kwargsで自由に引数追加


ということで、本題の引数を可変長引数kwargsで追加する方法について解説する。といっても簡単に設定することができ、関数の引数に**kwargsを設定するだけ。超お手軽。

def scatter_kwargs(x, y, **kwargs):
    d = go.Scatter(
        x=x, y=y,  # x, yは指定は確定
        **kwargs,  # 可変長引数で展開して自動的に代入
    )

    return d

また、実際に関数を使用する際には引数とその値を入れるだけ。今回は線のグラフにするのか、線とマーカーのグラフにするのかなどを設定するmodeを引数として設定した。markersにしたので、出来上がるグラフは点のグラフ。

# 可変長引数だから自由に引数を追加可能
name = 'kwargs'
plot = [
    scatter_kwargs(
        x=x, y=y, name=name,
        mode='markers',  # mode='markers'で線なしの点だけのグラフに変更
    ),
]

fig = go.Figure(data=plot)
fig.show()
save(fig=fig, config=None, save_name=name)

dictでネストされた引数はアンダースコア_を使用しても良い


なら、ネストされた引数はどうするのか。例えば、マーカーのサイズを変更したい時に、直接sizeと入力してしまうとそんな引数ないということでエラーとなる。

# ただし、dictでネストされた設定はそのままではエラー
plot = [
    scatter_kwargs(
        x=x, y=y,
        size=20,  # 希望はマーカー(シンボル)のサイズを20に
    ),
]
# ValueError: Invalid property specified for object of type plotly.graph_objs.Scatter: 'size'

ならどうすればいいかと言えばもちろんdictでネストしてもいい。

# dictでネストしてもいい
plot = [
    scatter_kwargs(
        x=x, y=y,
        marker=dict(size=20),  # 希望はマーカー(シンボル)のサイズを20に
    ),
]

しかし、毎回dictと書いてカッコを書いてとなると面倒。そこで使えるのが_を使用する方法。さっきと同じ方法だ。ここではmarker_sizeとすればいい。

# dictでネストしたいなら_を使用する
name = 'kwargs_marer_size'
plot = [
    scatter_kwargs(
        x=x, y=y,
        marker_size=20,  # アンダースコアでmarker=dict(size=20)を表現
    ),
]

fig = go.Figure(data=plot)
fig.show()
save(fig=fig, config=None, save_name=name)

kwargsを使用してグラフをカスタム


ということで、総復習のような形でカスタムしたグラフを書いてみる。基本的にはマーカーと線についてのみだが、もちろんmodeやマウスをプロット上に置いたとき(ホバー)の設定も行うことができる。

# 色々カスタムする
name = 'kwargs_options'
plot = [
    scatter_kwargs(
        x=x, y=y,
        marker_size=20,  # マーカーサイズ
        marker_color='violet',  # マーカーの色
        marker_symbol='diamond-x',  # マーカーの形状
        marker_line_color='blue',  # マーカーの線の色
        marker_line_width=1,  # マーカーの線の太さ
        # dictで指定しても大丈夫
        line=dict(
            color='mediumvioletred',  # 線の色
            dash='dashdot',  # 線種(一点鎖線)
        )
    ),
]
fig = go.Figure(data=plot)
fig.show()
save(fig=fig, config=None, save_name=name)

なお、関数の呼び出し時に引数が多いと見づらいかもしれない。そんな時は指定したい引数をdictに入れておいて、関数呼び出し時にそれを展開すればいい。

# plotは以下と同じ
dct = dict(
    x=x, y=y,
    marker_size=20,  # マーカーサイズ
    marker_color='violet',  # マーカーの色
    marker_symbol='diamond-x',  # マーカーの形状
    marker_line_color='blue',  # マーカーの線の色
    marker_line_width=1,  # マーカーの線の太さ
    # dictで指定しても大丈夫
    line=dict(
        color='mediumvioletred',  # 線の色
        dash='dashdot',  # 線種(一点鎖線)
    )
)
plot = [scatter_kwargs(**dct)]

レイアウトでもkwargsは使用可能


ここまではプロットの方で可変長引数kwargsを使用してグラフの設定を追加する方法について解説してきた。が、しかし、実はレイアウトでも同じようなことができる。

そりゃどちらもdict形式でグラフの設定を行うからできるっちゃできる。なので、レイアウトでも**kwargsとすることで後から設定を追加できる。ここでは軸ラベルと縦軸の表示範囲を設定。

def layout_kwargs(**kwargs):
    # 可変長引数で展開して自動的に代入
    layout = go.Layout(**kwargs,)

    return layout

name = 'layout_kwargs'
plot = [scatter_kwargs(x=x, y=y, marker_size=20,), ]

# レイアウトも可変長引数で追加可能
layout = layout_kwargs(
    xaxis_title='x',  # 横軸タイトルを設定
    yaxis=dict(title='yyy', range=(0, 30))  # 縦軸タイトルと表示範囲を設定
)
fig = go.Figure(data=plot, layout=layout)
fig.show()
save(fig=fig, config=None, save_name=name)

注意、2種類のkwargsは使用不可

def miss(**kwrgs, **kwrgs2):
    print(kwrgs)
    print(kwrgs2)
#     def miss(**kwrgs, **kwrgs2):
#                       ^
# SyntaxError: invalid syntax

最後にkwargsを使用するときの注意点について書いていく。それは、複数種類のkwargsを同時に使用することができないということ。そりゃ、同時に指定されたらどの引数がどっちのkwargsかわからんくなる。

ということで、文法エラーのSyntaxErrorが出力される。

気づいてしまった、この便利さに

今回はplotlyと可変長キーワード引数kwargsを使用して、後から自由に引数を追加する方法について解説した。これは調べて知ったわけでも聞いたわけでもなく、自分でふと気がついたもの。

何がきっかけかはわからないが、突然こんな画期的な手法を思いついてしまった自分が怖いくらい。これからはこれを使って、関数定義時の引数をスッキリ見せるようにするだろう。日々の気づきが成長につながる。

関連記事

【inspect&引数名取得】defのパラメータ名を取り出す

こんな人にオススメ curve_fitで得 ...

続きを見る

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

こんな人にオススメ plotlyを使ī ...

続きを見る

【python&関数化】defとかargsとかを使って関数を作成する

こんな人にオススメ pythonのdefっ ...

続きを見る

【plotly&make_subplots】pythonのplotlyで複数グラフを1つの画像に描く

こんな人にオススメ 以前の ...

続きを見る

スイッチボット

2022/9/11

【SwitchBotロックレビュー】これからのスタンダードになりうるスマートロック

こんな人にオススメ SwitchBotからスマートロック「SwitchBotロック」が発売された ...

生活に役立つ

2022/10/25

【メガネ厳選】クソ便利に使っているサービスやアイテム達

このページでは執筆者「メガネ」が実際に使って便利だと感じているサ ...

マウス

2022/9/11

【Logicool MX ERGO vs MX Master 3】ERGOをメインにした決定的な理由

こんな疑問・お悩みを持っている人におすすめ 執筆者はLogicoolのハイエンӠ ...

完全ワイヤレスイヤホン(TWS)

2022/11/21

【ながら聴きイヤホン比較】SONY LinkBuds、ambie、BoCoはどれがおすすめ?

こんな人におすすめ 耳を塞がない開放型のイヤホンに完全ワイヤレスӟ ...

macOSアプリケーション

2022/10/15

【M1 Mac】MacBook Proに入れている便利でニッチなアプリを21個紹介する

こんな人におすすめ MacBookを購入してLINEとか必要最低限のアプリは入れた。 ...

完全ワイヤレスイヤホン(TWS)

2022/10/23

【SENNHEISER MOMENTUM True Wireless 3レビュー】高レベルでバランス型の高音質イヤホン

こんな人におすすめ SENNHEISER MOMENTUM True Wireless 3って実際のところどうなの? 評判は良い ...

完全ワイヤレスイヤホン(TWS)

2022/11/21

【SONY WF-1000XM4レビュー】神とゴミのハーフ&ハーフ

こんな人におすすめ SONYのフラグシップモデル「SONY WF-1000XM4」ってどれくらい性 ...

完全ワイヤレスイヤホン(TWS)

2022/8/19

【Nothing ear (1)レビュー】ライトな完成度、アップデートに期待

こんな人にオススメ 完全ワイヤレスイヤホン(TWS)でスケルトンボディ ...

Pythonを学びたいけど独学できる時間なんてない人へのすゝめ

執筆者は大学の研究室・大学院にて独学でPythonを習得した。

でも社会人になったら独学で行うには時間も体力もなくて大変だ。

時間がない社会人だからこそプロの教えを乞うのが効率的。

ここでは色んなタイプに合ったプログラミングスクールの紹介をする。

  • この記事を書いた人

メガネ

ベンチャー企業のWebエンジニア駆け出し。独学のPythonで天文学系の大学院を修了→新卒を1.5年で辞める→転職→今に至る。
常時金欠のガジェット好きでM1 MacBook Pro x Galaxy S22 Ultraの狂人。
人見知りで根暗だったけど、人生楽しもうと思って良い方向に狂う→人生が楽しい

ガジェットのレビューとPythonコードを記事にしています。ぜひ楽しんでください🦊
自己紹介と半生→変わって楽しいの繰り返し

-Plotly全般
-, , ,