📊

plotlyで描画するときはmodeを明示しよう(戒め)

2023/07/28に公開

タイトル通り。2時間くらいハマった。
公式を読まなかった自身への戒めを込めて記事にします。

◎本記事の結論
折れ線グラフを作るときはmode="lines"かmode="line+markers"を明示する。
理由: modeはデータ数によってデフォルト値が変化するため

  • 20個未満: mode="lines+markers"
  • 20個以上: mode="lines"

plotlyとは

グラフ描画を行うライブラリ
https://plotly.com/python/

pythonだとmatplotlibもよく使われます。
https://matplotlib.org/

私の用途ではどっち使ってもあまり違いは無さそうでした。
plotlyは複数の言語をサポートしているのが強みかなと思います。

何にハマっていたのか

折れ線グラフの線にマーカーを足して描画をします。

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

# データ数10のランダムな折れ線グラフを描画
# 参考:https://plotly.com/python/line-charts/
N = 10
random_x = np.linspace(0, 1, N)
random_y0 = np.random.randn(N) + 5

plot = [
    go.Scatter(
        x=random_x,
        y=random_y0,
        name="sampleA",
        line=dict(color="blue", dash="solid"),
        marker=dict(symbol="circle-open"),
    ),
]

# 画像出力
fig = go.Figure(data=plot)
pio.write_image(fig, "./output.png", format="png")

n10

線の値に対して円が描画されているのがマーカー。
これを描画したかったが、ある時点を境にマーカーだけ描画されなくなりました。

あるデータ数を超えると描画されなくなる…

先ほどのコード
Nを変化させる事で任意のデータ数で描画ができます。
N=100にするとこうなります。

n100
N=100のとき

マーカー指定したのに描画されなくなりました。

データ数によって描画されなくなるのか…?
と思いNの数値を変化させると…

N=20
n20
N=20のとき

N=19
n19
N=19のとき

データ数が20個を境に描画されなくなる事が分かりました。

公式ドキュメントに書いてあった仕様

データ数が20個を境に描画されなくなるようです。
調べた結果を基に、公式ドキュメントで検索したらここに辿り着きました。

https://plotly.com/python/reference/scatter/#scatter-mode

modeについての説明です。
ここを読んでいくと

If there are less than 20 points and the trace is not stacked then the default is "lines+markers". Otherwise, "lines".

20という数値を発見。chatGPTに翻訳依頼。

データが20点未満でトレースがスタックされていない場合は、デフォルトは "lines+markers" です。それ以外の場合は "lines" です。

自分で調べた内容が丸ごと書いてありました。しかも解決策つき。
想定した仮説通り、データ数20未満かに応じて描画モードのデフォルト値が変わるようです。

検証&対策

原因が分かったので、対策を含めて検証。
mode指定したパターンと指定しないパターンでの差異を比較します。

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

N = 20
random_x = np.linspace(0, 1, N)
random_y0 = np.random.randn(N) + 5
random_y1 = np.random.randn(N)

plot = [
    # modeを指定してデータ数20
    go.Scatter(
        mode="lines+markers",
        x=random_x,
        y=random_y0,
        name="sampleA",
        line=dict(color="blue", dash="solid"),
        marker=dict(symbol="circle-open"),
    ),
    # modeを指定せずデータ数20
    go.Scatter(
        x=random_x,
        y=random_y1,
        name="sampleB",
        line=dict(color="red", dash="solid"),
        marker=dict(symbol="circle-open"),
    ),
]

fig = go.Figure(data=plot)
pio.write_image(fig, "./output.png", format="png")

出力結果はこちら

mode
sampleAがmode指定 sampleBがmode無指定 データ数は20

mode="lines+markers"でマーカーが描画されている事が確認できました。

まとめ

冒頭に書いた結論通り。
modeは明示して作成すること。

今回は公式ドキュメントに記述あったため、すぐ調べれば答えは出ていました。

ここからは筆者の意見。
ハマった時は、すぐ調べる前に自分で色々検証するのも悪くないと考えます。
原因究明時は、仮説→検証ループで目星をつける訓練になるし
原因が分かれば、よりクリティカルな検索ワードを入れられるからです。

…という、自分の言い訳もそっとのせておきます。

参考文献

Discussion