こんな人にオススメ
plotly
でグラフを描くときに関数を使用するけど、設定したい引数が多すぎて関数を定義するときに長くなっちゃう。
かといって引数を使用しないと関数としての魅力が激減してしまう。どうしたらいい?
ということで、今回は関数を使用してplotly
のグラフを描く際に便利な、関数と可変長引数kwargs
について解説する。kwargs
をうまく活用することで、関数自体がスッキリするし、後から自由に引数を追加することも。
突然アイデアが降ってきた今回の記事のkwargs
、これから多用しそうなくらい便利だった。知っていた人からしたら当たり前だし、簡単に思いつきそうな内容だけど、知るのと知らないのでは雲泥の差。執筆者は進化した(大袈裟)、
python環境は以下。
- Python 3.9.6
- plotly 5.1.0
- plotly-orca 3.4.2
目次(クリック・タップでジャンプ)
作成したコード全文
下準備
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のグラフ即席作成コード
続きを見る
また、使用するデータは適当に作成した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】グラフのツールバーを編集する
続きを見る
引数を設定すると便利だが、関数の引数が長くなる
まずは、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
続きを見る
また、初期値を設定したので、その初期値のままでいい部分は指定しなくてもいい。以下ではsymbol
とmarker_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のパラメータ名を取り出す
続きを見る
-
【plotly&table+scatter】subplotsで表と散布図を同時にグラフ化
続きを見る
-
【python&関数化】defとかargsとかを使って関数を作成する
続きを見る
-
【plotly&make_subplots】pythonのplotlyで複数グラフを1つの画像に描く
続きを見る