カテゴリー

当サイトはアフィリエイトプログラムによる収益を得ています〈景品表示法に基づく表記です)

Plotly全般

【plotly&工夫】楽にグラフを描くためのplotlyの関数化

2021年7月22日

こんな人にオススメ

plotlyでグラフを描いているんだけど、設定する項目が多すぎてコードが長くなりがち。

どうにか楽してコードを短くしたい。

ということで、今回は執筆者が最近実践しているplotlyのコード短縮について解説する。既に知っている人や実践している人にとっては今更かよ感はあるけど、今更なんよ。

もっと早く気づけば、1つのグラフに300行も使わなくても良かったと今では思う。困ったものだ。

で、どうやってコードを短くするかというと、同じ処理は関数化してしまうということ。要するに雛形・テンプレートを予め作成して、これにその時々のデータを設定するということ。

どんな感じかは本記事で明らかになる。python環境は以下。

  • Python 3.9.4
  • numpy 1.20.3
  • matplotlib 3.4.2
  • plotly 4.14.3
  • plotly-orca 3.4.2

運営者のメガネです。YouTubeTwitterInstagramも運営中。自己紹介お問い合わせページあります。

運営者メガネ

下準備

import sys
import numpy as np
import matplotlib
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

x = np.arange(0, 10, 0.2)

まずは今回解説するコードの下準備のimport関連。いつも通りのメンツ。plotly_layout_templateは執筆者が作成したplotlyのテンプレート。詳しくは以下。

テンプレート適用後のplotlyでのグラフ
【plotlyテンプレート】plotlyのグラフ作成テンプレート

続きを見る

コードを下に続けてグラフ化


今回はdictにデータを複数個、格納してグラフを作成する。今は要素数は3つだけだが執筆者の研究では最低でも9つで、このようなdictが数十個も存在していた。

データは線形と三角関数

y = {
    'y = x': x,
    'y = sin(x)': np.sin(x),
    'y = cos(x)': np.cos(x),
}

まずは上のdictにある直線とsin関数、cos関数をplotlyを使ってグラフ化してみる。

グラフの表示と保存は引数で管理

graph_y(
    pic=True,
    save=True,
)

ここで1つの工夫としてグラフの表示と保存は引数で行う。どういうことかというと、作成したグラフを実際にブラウザ上で表示するか否かと、作成したグラフをファイルとして保存するか否かをdefの関数の引数で決めるということ。

こうすることで、関数を使用するときに引数部分の内容を変更するだけでグラフの挙動を変更することができる。イメージは上のコード。これを含めた全体コードを書くと以下のようになる。

def graph_y(pic=False, save=False):
    """dictデータを各keyごとにプロット

    Parameters
    ----------
    pic : bool, optional
        作成したグラフを表示するか否か, by default False
    save : bool, optional
        作成したグラフを保存するか否か, by default False
    """

    plot = []
    for num, (name, val) in enumerate(y.items()):
        color = cm.jet_r(num / len(y))
        color = plotly.colors.convert_to_RGB_255(color) + (1,)
        color = f"rgba{color}"

        name = name
        d = go.Scatter(
            mode='lines+markers',
            x=x, y=val,
            name=name,
            marker=dict(symbol='circle',),
            line=dict(dash='solid', color=color,),
            hovertemplate=f"{name}<br>"
            + '%{x} <br>'
            + '%{y} <br>'
            + "<extra></extra>",
        )
        plot.append(d)

    layout = go.Layout(
        template=template.plotly_layout(),
        title=dict(text='',),
        xaxis=dict(title='',),
        yaxis=dict(title='',),
    )

    fig = go.Figure(data=plot, layout=layout)
    if pic:
        fig.show(config=template.plotly_config())

    # 作成したグラフを保存
    if save:
        pio.write_html(
            fig,
            'graph_y.html', auto_open=False,
            config=template.plotly_config(),
        )
        pio.write_image(fig, 'graph_y.png')

# 欲しい情報だけ指定
graph_y(
    pic=True,
    save=True,
)

foryの各グラフを取り出して、colorでそれぞれのforで色を決定。go.Scatterでプロットデータを作成したのち、go.Layoutでレイアウトを決めてgo.Figureでこれらを合体させて出力。

ここで引数のpicsaveが登場する。picTrueとすることで作成したグラフをブラウザ上に表示することができ、saveTrueにすることで作成したグラフをファイルとして保存。

グラフの保存だけしたい時は以下のようにpicをコメントアウトしたりFalseにしたりすればいい。

# picをコメントアウト
graph_y(
    # pic=True,
    save=True,
)

# picをFalseに
graph_y(
    pic=False,
    save=True,
)

# picのデフォルトはFalse
graph_y(
    save=True,
)

でも長くないか?

でも考えてほしい。上のコードはあまりにも長すぎないか?50行は超える。これはもっと短くしたほうが見やすいように感じる。

執筆者の使っているMacbook Pro 13インチでは51行分表示するようにフォントサイズを設定している。しかし、大半の人はもっとフォントサイズは大きいだろうから全貌が見えにくいだろう。

複数プロットになるともっとダラダラ長い


さっきの例だとコードが50行を超えていて長かった。でも100行行ってないし大丈夫だろうと思ったけど、プロットする種類が増えたらどうだろうか。要するにyだけではなくzという新たなデータもプロットするならどうだろうか。

新たなデータを追加

z = {
    'z = x<sup>0.5</sup>': x ** 0.5,
    'z = sin(0.5x)': np.sin(0.5 * x),
    'z = cos(0.5x)': np.cos(0.5 * x),
}

先程のyと同じように3つのデータを追加で作成した。dict名はz。このデータも追加でプロットしてみる。

2つのプロットを下に続ける

# yのプロット
for num, (name, val) in enumerate(y.items()):
    color = cm.Reds_r(num / len(y))
    color = plotly.colors.convert_to_RGB_255(color) + (1,)
    color = f"rgba{color}"

    name = name
    d = go.Scatter(
        mode='lines+markers',
        x=x, y=val,
        name=name,
        marker=dict(symbol='circle',),
        line=dict(dash='solid', color=color,),
        hovertemplate=f"{name}<br>"
        + '%{x} <br>'
        + '%{y} <br>'
        + "<extra></extra>",
    )
    plot.append(d)

# zのプロット
for num, (name, val) in enumerate(z.items()):
    color = cm.Blues_r(num / len(z))
    color = plotly.colors.convert_to_RGB_255(color) + (1,)
    color = f"rgba{color}"

    name = name
    d = go.Scatter(
        mode='lines+markers',
        x=x, y=val,
        name=name,
        marker=dict(symbol='square',),  # ここ変更
        line=dict(dash='dash', color=color,),  # ここ変更
        hovertemplate=f"{name}<br>"
        + '%{x} <br>'
        + '%{y} <br>'
        + "<extra></extra>",
    )
    plot.append(d)

さっきと同じように、y, zそれぞれでプロットのためのgo.Scatterを作成。単純にgo.Scatterのコード行数が2倍となる。よって、全体コードとしては以下になる。

こんなに長いコードは流石にだるい。100行には行ってないのでまだマシかもしれないが、プロット数が3つにも4つにもなったらさらに行数が必要になる。もちろんforでまとめることも可能だが、今回は関数を使用して簡略化してみる。

同じコードはdefで関数化

当たり前っちゃ当たり前だけど、同じことは定式化したら楽。マニュアルとかロボットとか予め決めたり、一部を指定したらあとは自動でこなしてくれる。これをプログラミングで実装するのが関数だ(全言語がそうとは限らないかもしれないが)。

go.Scatterを関数化

def scatter(x: np.ndarray, y: np.ndarray, name='',
            color=(1, 0, 0), symbol='circle', dash='solid', alpha=1.,):
    """横軸の値、縦軸の値より、plotlyのScatter配列を作成

    Parameters
    ----------
    x : np.ndarray
        横軸の値
    y : np.ndarray
        縦軸の値
    name : str, optional
        プロットの名称, by default ''
    color : tuple, optional
        プロットのrgb(R, G, B), by default (1, 0, 0)
    symbol : str, optional
        プロットのマーカー, by default 'circle'
    dash : str, optional
        プロットの線種, by default 'solid'
    alpha : float, optional
        プロットの透明度, by default 1.

    Returns
    -------
    go_scatter.Scatter
        plotlyのgo.Scatterの配列
    """

    color = plotly.colors.convert_to_RGB_255(color) + (alpha,)
    color = f"rgba{color}"

    d = go.Scatter(
        mode='lines+markers',
        x=x, y=y,
        name=name,
        marker=dict(symbol=symbol),
        line=dict(dash=dash, color=color,),
        hovertemplate=f"{name}<br>"
        + '%{x}<br>'
        + '%{y}<br>'
        + "<extra></extra>",
    )
    return d

まずはgo.Scatterを予め関数化。引数は以下。

  • x: 横軸のデータ配列
  • y: 縦軸のデータ配列
  • name: プロットの名前(初期値: ''
  • color: プロットの色。(R, G, B) = (赤, 緑, 青)として入力。0-1の範囲。(初期値: (1, 0, 0): 赤)
  • symbol: プロットマーカーの種類(初期値: circle(円形))
  • dash: プロット線の種類(初期値: solid(実線))
  • alpha: プロット線の透明度(初期値: 1.(薄くならない))

色についてはmatplotlibの方が慣れているのと色の種類が多かった(記憶)ので、matplotlibのRGB方式で0から1の値で色を作成。しかしplotlyでは0から255までなのでこれを変換する必要がある。

シンプルに255をかければいいだろうけど、ちょうど関数があるので使用する。(R, G, B)でも(R, G, B, a)でも出力は(R, G, B)なので(alpha,)で透明度の情報を付加している。

plotly.colors.convert_to_RGB_255(color)

print(plotly.colors.convert_to_RGB_255((1, 0, 1)))  # (R, G, B)
# (255, 0, 255)
print(plotly.colors.convert_to_RGB_255((1, 0, 1, 1)))  # (R, G, B, a)
# (255, 0, 255)

関数を呼び出すときは以下の感じで書く。この場合は直線のグラフで、名前がplot1で色はマゼンタっぽくなり、マーカーは四角で線種は点線、透明度は0.5で薄くなる。

返り値returndとしてgo.Scstterなので、ここでもわかりやすいように戻ってきた値をdに格納している。

d = scatter(
    x=[1, 2, 3], y=[10, 20, 30], name='plot1', color=(1, 0, 1),
    symbol='square', dash='dot', alpha=0.5,
)

複数dictから自動でプロットデータを作成する関数

def set_scatter(plot: list, dct: dict, symbol='circle', cmap=cm.Reds_r,
                prefix='', suffix='', dash='solid', alpha=1.,):
    """dictで作成した縦軸のデータをforで回してgo.Scatterの配列を作成
    その後go.Scatterの配列を入力値plotのlistに入れる

    Parameters
    ----------
    plot : list
        plotlyのgo.Figureのdataに対応するlist
    dct : dict
        縦軸のデータを入れたdict
    symbol : str, optional
        プロットのマーカー, by default 'circle'
    cmap : cm.colors.LinearSegmentedColormap, optional
        プロットの色合いを示す、matplotlib.cmの名称, by default cm.Reds_r
    prefix : str, optional
        プロットのnameの前につける接頭辞, by default ''
    suffix : str, optional
        プロットのnameの後につける接尾辞, by default ''
    dash : str, optional
        プロットの線種, by default 'solid'
    alpha : float, optional
        プロットの透明度, by default 1.
    """

    for num, (name, val) in enumerate(dct.items()):
        color = cmap(num / len(dct))

        name = f"{prefix}{name}{suffix}"
        # さっき作成した関数を使用
        d = scatter(x=x, y=val, name=name, color=color, symbol=symbol,
                    dash=dash, alpha=alpha,)
        plot.append(d)

今回はdictのデータを1つずつプロットしていくので、これも関数化してみる。引数は以下。

  • plot: 作成したgo.Scatterのデータを格納するlist。最終的にgo.Figureに渡す。
  • dct: 作成したいプロットの名前と縦軸のデータの入ったdict
  • symbol: プロットマーカーの種類(初期値: circle(円形))
  • cmap: 引数dctのプロットの色をmatplotlib.cmの色で指定(初期値: cm.Reds_r
  • prefix: プロット名の初めに固定でつける接頭辞(初期値: ''
  • suffix: プロット名の最後に固定でつける接尾辞(初期値: ''
  • dash: プロット線の種類(初期値: solid(実線))
  • alpha: プロット線の透明度(初期値: 1.(薄くならない))

まずはforでデータ数num0から勘定、dctkeysvaluesを取得。nummatplotlib.cmdctの要素ごとに色を作成。

for num, (name, val) in enumerate(dct.items()):
    color = cmap(num / len(dct))

prefixsuffixについては、dctkeysに加えて統一された文言を文頭もしくは文末につけたい時に使用。dctkeysの内容を変更したくない時などには便利。デフォルトが''なので指定しなければ何もつくことはない。

ただし、prefixを設定する時は最後に、suffixを設定するときは初めに空白を入れないと文字がくっつくので注意。

prefix = 'prefix'
name = 'name'
suffix = 'suffix'
name = f"{prefix}{name}{suffix}"
print(name)
# prefixnamesuffix

prefix = 'prefix '  # 最後に半角スペース
name = 'name'
suffix = '\\t\\tsuffix'  # 初めにタブ
name = f"{prefix}{name}{suffix}"
print(name)
# prefix name		suffix

あとはさっき作成したscatter関数を使用すれば簡単にdict形式のデータをgo.Scattterに変換することが可能。最後にplotにデータを格納することで更なる自動化が可能。

scatter関数とset_scatter関数を使用したグラフ

def graph_p_def(pic=False, save=False,):
    """作成したscatter関数、set_scatter関数を使用してy, zをグラフ化

    Parameters
    ----------
    pic : bool, optional
        作成したグラフを表示するか否か, by default False
    save : bool, optional
        作成したグラフを保存するか否か, by default False
    """

    plot = []
    # yのプロット
    set_scatter(plot=plot, dct=y,)
    # zのプロット
    set_scatter(
        plot=plot, dct=z,
        symbol='square', cmap=cm.Blues_r, dash='dash',
    )

    layout = go.Layout(
        template=template.plotly_layout(),
        title=dict(text='',),
        xaxis=dict(title='',),
        yaxis=dict(title='',),
    )

    fig = go.Figure(data=plot, layout=layout)

    if pic:
        fig.show(config=template.plotly_config())

    # 作成したグラフを保存
    if save:
        pio.write_html(
            fig,
            'graph_p_def.html', auto_open=False,
            config=template.plotly_config(),
        )
        pio.write_image(fig, 'graph_p_def.png')

graph_p_def(
    pic=True,
    save=True,
)

上で解説したscatter関数とset_scatter関数を使用したグラフコードが上。だいぶスッキリしたんじゃないだろうか。これで50行は切った。このコードでできるグラフは先ほどと同じだが一応載せておく。


レイアウトもグラフ保存も関数化

さっきのコードでプロット部分を関数を使用して簡略化することができた。しかし、よくよく考えればレイアウト部分も関数化できそうだし、グラフの保存も関数化できそうだ。

ここではレイアウトとグラフ保存の関数化も行う。

go.Layoutの関数化

def set_layout(title='', xtitle='', ytitle='',
               xrange=None, yrange=None, xtype='linear', ytype='linear'):
    """go.Layoutの設定

    Parameters
    ----------
    title : str, optional
        グラフタイトル, by default ''
    xtitle : str, optional
        横軸ラベル, by default ''
    ytitle : str, optional
        縦軸ラベル, by default ''
    xrange : list or tuple, optional
        横軸の初期表示範囲, by default None
    yrange : list or tuple, optional
        縦軸の初期表示範囲, by default None
    xtype : str, optional
        横軸のタイプ(logかlinearなど), by default 'linear'
    ytype : str, optional
        縦軸のタイプ(logかlinearなど), by default 'linear'

    Returns
    -------
    go._layout.Layout
        plotlyのgo.Layout配列
    """

    layout = go.Layout(
        template=template.plotly_layout(),
        title=dict(text=title,),
        xaxis=dict(title=xtitle, range=xrange, type=xtype,),
        yaxis=dict(title=ytitle, range=yrange, type=ytype,),
    )

    return layout

レイアウトについてはgo.Layoutで指定することができるが、設定項目がエグいくらい多い。そこで、ここでは普段から執筆者がよく使う設定のみを引数として使用する。引数は以下。

  • title: グラフタイトル(初期値: ''
  • xtitle: 横軸ラベル(初期値: ''
  • ytitle: 縦軸ラベル(初期値: ''
  • xrange: 横軸の初期表示範囲(初期値: None
  • yrange: 縦軸の初期表示範囲(初期値: None
  • xtype: 横軸の形式(線形かlogかとか)(初期値: 'linear'
  • ytype: 縦軸の形式(線形かlogかとか)(初期値: 'linear'

使い方はscatterの時と同様で、以下のように書けばいい。

layout = set_layout(
    title='これはタイトル', xtitle='X', ytitle='Y',
    xrange=(-0.2, 10), yrange=(-1.2, 1.2),
)

設定しなくていい項目は初期値があるなら書かなくてもいい。

pio.write_を関数化

def set_save(fig, file_name: str, img_extension='png'):
    pio.write_html(
        fig,
        f"{file_name}.html", auto_open=False,
        config=template.plotly_config(),
    )
    pio.write_image(fig, f"{file_name}.{img_extension}")

グラフの保存はpio.write_で行っているが、グラフの保存に必要なのはどのグラフをどのファイル名で保存するかという2点。ここでは拡張子を別で指定できるようにしているが、重要なのはこの2点。

なので、引数に2点+拡張子を入れた関数を作成。もちろん静止画がいらない場合はpio.write_imageは決して構わないし、htmlがいらないならpio.write_htmlを消して構わない。

レイアウトとグラフ保存を関数化したグラフ

a = {
    'a = sin(x)': np.sin(x),
    'a = cos(x)': np.cos(x),
    'a = tan(x)': np.tan(x),
}

ということで、レイアウトとグラフ保存を関数化した後のグラフを作成する。データは少し変えて三角関数のみとした。

def graph_pls_def(pic=False, save=False):
    """プロット、レイアウト、保存を設定した関数からグラフを作成

    Parameters
    ----------
    pic : bool, optional
        作成したグラフを表示するか否か, by default False
    save : bool, optional
        作成したグラフを保存するか否か, by default False
    """

    plot = []
    set_scatter(
        plot=plot, dct=a,
        symbol='hexagram', cmap=cm.cool, dash='dashdot', alpha=0.5,
    )

    layout = set_layout(
        title='trigonometric functions: 三角関数', xtitle='x', ytitle='y',
        xrange=(-0.2, 10), yrange=(-1.2, 1.2),
    )

    fig = go.Figure(data=plot, layout=layout)

    if pic:
        fig.show(config=template.plotly_config())
    if save:
        set_save(fig=fig, file_name='graph_pls_def', img_extension='png')

graph_pls_def(
    pic=True,
    save=True,
)

かなりスッキリした。これでパッと見の印象も良くなる。ここではset_scatterなどの関数には直接aなどの引数を入れているが、もちろんこれもgraph_pls_defの引数とすれば、graph_pls_def自体を使いまわすことが簡単になる。これについては最後に行う。


色をRGBとstrの入力でそれぞれ自動計算

話がガラリと変わるが、プロットの色をRGBのtupleでも'red'のようなstrでも対応させる方法がないだろうかということを知った。最後はこれについて解説する。

plotlyの0-255変換にはstrは入れられない

base_color = 'limegreen'

# plotly.colors.convert_to_RGB_255は(R, G, B)を0-1から0-255にする関数
# よって色のstrを入れることはできない
plotly_color = plotly.colors.convert_to_RGB_255(base_color)
# TypeError: can't multiply sequence by non-int of type 'float'

ことの発端はplotly.colors.convert_to_RGB_255strでの色を入れたらエラーが出たということ。今まではmatplotlib.cmのカラーマップ用の色を使用していたが、'red'のように色を直接指定したい時があった。

しかし上にあるようにstrでありfloatではないのでエラーが出る。floattupleだとこのエラーは出ずに正常に処理される。

# R, G, Bを設定すると計算可能
plotly_color = plotly.colors.convert_to_RGB_255((1, 0.5, 0))
print(plotly_color)
# (255, 128, 0)

matplotlibstrの色をRGBに変換

# matplotlib.colors.ColorConverter.to_rgbで色のstrをrgbに変換することが可能
rgb_color = matplotlib.colors.ColorConverter.to_rgb(base_color)
print(rgb_color)
# (0.19607843137254902, 0.803921568627451, 0.19607843137254902)
print(type(rgb_color))
# <class 'tuple'>

そんな中、matplotlibstrの色をRGBに変換できる関数を見つけた。matplotlib.colors.ColorConverter.to_rgbだ。これにstrの色を入れることでその色が0から1の間のRGBとして出力される。

これならplotlyの255RGB変換が可能なので、変換してみる。

# (R, G, B)の配列で出力できたのでplotly用に変換することが可能に
plotly_color = plotly.colors.convert_to_RGB_255(rgb_color)
print(plotly_color)
# (50, 205, 50)

できた。一応確認のためにグラフ化してみる。

色をRGBとstrの入力でそれぞれ自動計算したscatter

try:  # colorが(R, G, B)形式の場合
    color = plotly.colors.convert_to_RGB_255(color)
except TypeError:  # colorが色のstrの場合
    color = matplotlib.colors.ColorConverter.to_rgb(color)

これまでの処理でわかったことをまとめると以下。

  • (R, G, B)の色となっている場合: plotly.colors.convert_to_RGB_255(color)
  • strの色となっている場合: matplotlib.colors.ColorConverter.to_rgb(color)

なので上のコードで書いたように、try文でエラーが出るか否かで処理を分岐。適切な処理が行われるようにした。以下でgo.Scatterをリニューアル。

def scatter_renewal(x: np.ndarray, y: np.ndarray, name='',
                    color=cm.jet, symbol='circle', dash='solid', alpha=1.,):
    """横軸の値、縦軸の値より、plotlyのScatter配列を作成

    Parameters
    ----------
    x : np.ndarray
        横軸の値
    y : np.ndarray
        縦軸の値
    name : str, optional
        プロットの名称, by default ''
    color : tuple, optional
        プロットのrgba(R, G, B, a), by default (1, 0, 0)
    symbol : str, optional
        プロットのマーカー, by default 'circle'
    dash : str, optional
        プロットの線種, by default 'solid'
    alpha : float, optional
        プロットの透明度, by default 1.

    Returns
    -------
    go_scatter.Scatter
        plotlyのgo.Scatterの配列
    """

    try:  # colorが(R, G, B)形式の場合
        color = plotly.colors.convert_to_RGB_255(color)
    except TypeError:  # colorが色のstrの場合
        color = matplotlib.colors.ColorConverter.to_rgb(color)

    color = f"rgba{color + (alpha,)}"

    d = go.Scatter(
        mode='lines+markers',
        x=x, y=y,
        name=name,
        marker=dict(symbol=symbol),
        line=dict(dash=dash, color=color,),
        hovertemplate=f"{name}<br>"
        + '%{x}<br>'
        + '%{y}<br>'
        + "<extra></extra>",
    )
    return d

色をRGBとstrの入力でそれぞれ自動計算したグラフ

def graph_color_renewal(x: np.ndarray, y: np.ndarray, file_name: str, name='',
                        color=(1, 0, 0), symbol='circle', dash='solid', alpha=1.,
                        title='', xtitle='', ytitle='',
                        xrange=None, yrange=None,
                        xtype='linear', ytype='linear',
                        img_extension='png', pic=False, save=False):
    """x, yの値からグラフをプロット

    Parameters
    ----------
    x : np.ndarray
        横軸の値
    y : np.ndarray
        縦軸の値
    file_name : str
        グラフの保存名
    name : str, optional
        プロットの名称, by default ''
    color : tuple, optional
        プロットの色。(R, G, B)か色のstrで指定, by default (1, 0, 0)
    symbol : str, optional
        プロットのマーカー, by default 'circle'
    dash : str, optional
        プロットの線種, by default 'solid'
    alpha : float, optional
        プロットの透明度, by default 1.
    title : str, optional
        グラフタイトル, by default ''
    xtitle : str, optional
        横軸ラベル, by default ''
    ytitle : str, optional
        縦軸ラベル, by default ''
    xrange : tuple, optional
        横軸の表示範囲, by default None
    yrange : tuple, optional
        縦軸の表示範囲, by default None
    xtype : str, optional
        横軸のタイプ, by default 'linear'
    ytype : str, optional
        縦軸のタイプ, by default 'linear'
    img_extension : str, optional
        グラフの静止画の拡張子, by default 'png'
    pic : bool, optional
        作成したグラフを表示するか否か, by default False
    save : bool, optional
        作成したグラフを保存するか否か, by default False
    """

    plot = []
    d = scatter_renewal(
        x=x, y=y, name=name,
        color=color, symbol=symbol, dash=dash, alpha=alpha,
    )
    plot.append(d)

    layout = set_layout(
        title=title, xtitle=xtitle, ytitle=ytitle,
        xrange=xrange, yrange=yrange, xtype=xtype, ytype=ytype
    )

    fig = go.Figure(data=plot, layout=layout)
    if pic:
        fig.show(config=template.plotly_config())
    if save:
        set_save(fig=fig, file_name=file_name, img_extension=img_extension)

最後に総復習として、これまでの関数の引数を全てグラフの引数で指定しつつ、色をRGBとstrで指定する。なので、graph_color_renewalの引数は半端ないことになっているが、その代わりにグラフの中身はかなり少なくなっているだろう。

プロットデータをdctで入れる場合はdct用で処理が必要だけど、ここではとりあえず割愛する。引数は以下。

  • x: 横軸の値
  • y: 縦軸の値
  • file_name: グラフの保存名
  • name: プロットの名称(初期値: ''
  • color: プロットの色。(R, G, B)か色のstrで指定(初期値: (1, 0, 0)
  • symbol: プロットのマーカー(初期値: 'circle'
  • dash: プロットの線種(初期値: 'solid'
  • alpha: プロットの透明度(初期値: 1.)
  • title: グラフタイトル(初期値: ''
  • xtitle: 横軸ラベル(初期値: ''
  • ytitle: 縦軸ラベル(初期値: ''
  • xrange: 横軸の表示範囲(初期値: None
  • yrange: 縦軸の表示範囲(初期値: None
  • xtype: 横軸のタイプ(初期値: 'linear'
  • ytype: 縦軸のタイプ(初期値: 'linear'
  • img_extension: グラフの静止画の拡張子(初期値: 'png'
  • pic: 作成したグラフを表示するか否か(初期値: False
  • save: 作成したグラフを保存するか否か(初期値: False

で、引数が多いから大変そうかもしれないが、実際に使用する際には引数に必要な情報を入れるだけでいいのでシンプルになる。

以下で関数呼び出しの一例を示す。ここでは1引数ごとに改行しているがからかなり行数をとっているが、もちろん引数の後に次の引数を書いてもいい。

# 色をRGBで指定
color = (1, 0, 1)  # マゼンタっぽい色
graph_color_renewal(
    x=x,
    y=a['a = sin(x)'],
    file_name='graph_color_renewal_rgb',
    name='RGB=101',
    color=color,
    title='R : G : B = 1 : 0 : 1',
    xtitle='x',
    ytitle='y',
    img_extension='png',
    pic=True,
    save=True,
)


# 色をstrで指定
color = 'darkviolet'  # 暗い紫色
graph_color_renewal(
    x=x,
    y=a['a = sin(x)'],
    file_name='graph_color_renewal_str',
    name=f"color={color}",
    color=color,
    title=f"color = {color}",
    xtitle='x',
    ytitle='y',
    img_extension='png',
    pic=True,
    save=True,
)



関数化で楽ができそう

今回は最近行っているplotlyの関数化について解説した。関数化するのは結構面倒だけど、一回作成すると後でもサクッと使用できて全体コードの一貫性とシンプルかが見込める。

上であげたコードではまだ関数化できる、繰り返し処理があるのでまたなんとかして関数化して簡単にしたい。

しかし、重要なのはわかりやすさと簡潔さ。いくら関数化できたとしても使いにくかったり見にくかったら意味がない。昔の執筆者がそうで、1行でなるべくまとめようとしすぎて久しぶりの自分が見たらなんのこっちゃか。

どこかで見た言葉で「3日後の自分は他人」がある。プログラミング経験者でも過去の自分でもはたまたプログラミング初心者でもわかりやすいコードを書く必要があると感じる。まだまだ成長過程。

関連記事

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

続きを見る

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

続きを見る

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

続きを見る

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

続きを見る

ガジェット

2023/9/18

【デスクツアー2022下半期】モノは少なく、でも効率的に Desk Updating #0

今回はガジェットブロガーなのにデスク環境を構築していない執筆者の ...

ライフハック

2023/9/16

【Audible vs YouTube Premium】耳で聴く音声学習コンテンツを比較

ワイヤレスイヤホンが普及し耳で学習することへのハードルが格段に下 ...

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

2023/9/18

【SENNHEISER MOMENTUM True Wireless 3レビュー】全てが整ったイヤホン

今回は高音質・高機能なSENNHEISERのフラグシップ完全ワイヤレスイヤホン「SENNH ...

ライフハック

2023/3/11

【YouTube Premiumとは】メリットしかないから全員入れ

今回はYouTube Premiumを実際に使ってみてどうなのか、どんなメリット/デメリット ...

マウス

2023/8/17

【Logicool MX ERGOレビュー】疲れない作業効率重視トラックボールマウス

こんな人におすすめ トラックボールマウスの王道Logicool MX ERGOが気になるけどऩ ...

ベストバイ

2023/9/18

【ベストバイ2022】今年買って良かったモノのトップ10

2022年ベストバイ この1年を振り返って執筆者は何を買ったのか。ガジェッ& ...

スマホ

2023/1/15

【楽天モバイル×povo2.0の併用】月1,000円の保険付きデュアルSIM運用

こんな人におすすめ 楽天モバイルとpovo2.0のデュアルSIM運用って実際のとこ ...

マウス

2023/9/16

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

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

macOSアプリケーション

2022/9/30

【Chrome拡張機能】便利で効率的に作業できるおすすめの拡張機能を18個紹介する

こんな人におすすめ Chromeの拡張機能を入れたいけど、調べても同じような ...

macOSアプリケーション

2023/5/3

【Automator活用術】Macで生産性を上げる作業の自動化術

今回はMacに標準でインストールされているアプリ「Automator」を使ってできる ...

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

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

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

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

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

  • この記事を書いた人

メガネ

Webエンジニア駆け出し。独学のPythonで天文学系の大学院を修了。常時金欠のガジェット好きでM2 Pro MacBook Pro(30万円) x Galaxy S22 Ultra(17万円)使いの狂人。自己紹介と半生→変わって楽しいの繰り返しレビュー依頼など→お問い合わせ運営者情報、TwitterX@m_ten_pa、 YouTube@megatenpa、 Threads@megatenpa

-Plotly全般
-, ,