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

go(plotly.graph_objects) plotly

【Plotlyで散布図】go.Scatterglで大量のデータでグラフを作成する

2023年1月28日

今回はPythonのPlotlyで大量のデータを軽く扱うことができるgo.Scatterglの使い方とgo.Scatterとの比較を行う。1万以上のデータを散布図として扱う際はこの記事を参考にgo.Scatterglを活用してほしい。

もちろんgo.Scatterで1万のデータをグラフ化することも可能だが、グラフ作成時間やグラフ表示後の動きがカクカクして使いづらい。そんな時にWebGLを使用して動作するgo.Scatterglが活躍する。

本記事を通して1万や10万といった大量のデータを簡単に扱えるようになってほしい。

Python環境は以下。

  • Python 3.10.8
  • numpy 1.24.0
  • plotly 5.11.0
  • plotly-orca 3.4.2

参考になるサイト

Plotly公式

Qiita

Plotly Community Forum

本記事のコード全文

下準備のimport

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

まずは下準備としてのimport関連。今回はgoを使用する。pioplotlyでのグラフ保存用のライブラリ。保存の仕方は色々あるがpioはその1つだ。

また、本記事の最後にScatterScatterglの描画速度比較をするのでtimeimportしておく。

ScatterScatterglの違いと使い方

一般的に使われるgo.Scatterはsvg(ベクトル方式)を採用しており、グラフ化したりエクスポートした際に見やすくキレイな仕上がりになるのが特徴だ。また、一部の雑誌やWebサイトはこのsvgのみを公開している。

一方でgo.ScatterglはWebGL方式(ラスター方式)を採用しており、JavaScriptとGPUを使用して描画するので高速だ。GPUを使うことでCPUでは賄いきれない高処理負荷のグラフを描画可能。

ただしさらに一部のブラウザやPCではセキュリティの観点からWebGLが無効にされていたり学術論文では非推奨だ。

ということで私はgo.Scatterglを使うタイミングとしては以下の状況を考えている。

go.Scatterglを使うタイミングの目安

  • 10,000データを超えるグラフ
  • グラフの動きがモッサリしてきた
  • 見栄えより動作が重要

基本、大量のデータを扱わない限りは他のグラフと見た目上の差異がないgo.Scatterを使用するのが良いだろう。

Scatterglなら10万データをプロットしてもなめらか


ということで実際にgo.Scatterglを使用して10万データの散布図を作成してみた。ただ、このサイトに載せる際にデータ数が多すぎると表示できなかったので、サイト上ではデータ数を10,000に絞った。

実際にデータを触ってみるとわかるように、Scatterglを使うことで10,000データでも滑らかに動作させることが可能だ。

以下にScatterglで100,000データを描画し操作したときのgifを載せておく。

かなり滑らかに動作していることがわかるだろう。これだけ動かしているがデータ数は10万だ。

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

# 10万データをScatterglでプロットする

num = 100000
np.random.seed(1)
x = np.random.randn(num)
y = np.random.randn(num)

plot = [
    go.Scattergl(
        x=x, y=y, mode='markers',
        marker=dict(color=y, colorscale='jet'),
    )
]

layout =go.Layout(title='Scattergl')
fig = go.Figure(data=plot, layout=layout)
# グラフ全体とホバーのフォントサイズ変更
fig.update_layout(font_size=20, hoverlabel_font_size=20)
fig.show()

# グラフ保存
prefix = 'go-scattergl'  # 保存ファイル名の接頭辞
save_name = f"{prefix}_scattergl_{num}"
pio.orca.config.executable = '/Applications/orca.app/Contents/MacOS/orca'
pio.write_html(fig, f"{save_name}.html")
pio.write_image(fig, f"{save_name}.png")

Scatterだと動作がかなりもっさりする


一方で、通常のgo.Scatterを使用して10,000データの散布図を作成すると上のグラフのようになる。動かすことは可能だが、Scatterglに比べると少し引っ掛かりがあるように感じる。

これくらいのデータ数ならそこまで問題なく動作するが、これが10万データになるとかなりガクガクになってしまう。

拡大はできるものの縮小時のダブルクリックが動作しない。右上の家マークから初期表示に戻すことは可能だが、この際にも動作に遅れがある。

やはり大きなデータを扱う際にはgo.Scatterではなくgo.Scatterglを使うのが良いだろう。

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

# 10万データをScatterでプロットする

num = 100000
np.random.seed(1)
x = np.random.randn(num)
y = np.random.randn(num)

plot = [
    go.Scatter(
        x=x, y=y, mode='markers',
        marker=dict(color=y, colorscale='jet'),
    )
]

layout =go.Layout(title='Scatter')
fig = go.Figure(data=plot, layout=layout)
# グラフ全体とホバーのフォントサイズ変更
fig.update_layout(font_size=20, hoverlabel_font_size=20)
fig.show()

# グラフ保存
prefix = 'go-scattergl'  # 保存ファイル名の接頭辞
save_name = f"{prefix}_scatter_{num}"
pio.orca.config.executable = '/Applications/orca.app/Contents/MacOS/orca'
pio.write_html(fig, f"{save_name}.html")
pio.write_image(fig, f"{save_name}.png")

Scatterglの100万データで動作が遅くなる問題は解決

大データを散布図で扱うにはgo.Scatterglが便利という話をしてきたが、どうやら100万以上のデータ数の場合は動作がエラーになったり極端に遅くなっていたらしい。

ただしissueにあるように解決したとのこと。この事例は類似のものだが、実際にグラフを描画しても正常に描画・保存・表示ができた。100万データもあるのでちょっと引っかかりはあるが動く。

mode=’markers+text’でプロットの値を追加


基本的に大量のデータを扱うときはそのデータの多さから点プロットだけ表示することが多いが、プロットした値をプロット上に表示することも可能。

プロットの値を表示する詳しい方法は以下の[go.Scatterの記事に](https://programming.megatenpa.com/plotly/go/go-scatter/)て解説している通り引数modeで可能。今回は点プロットとテキストを表示したいのでmode=’markers+text’にした。go.Scatterでは引数texttext=yとすることでプロット点にその点のyの値が表示される。

【Plotlyで散布図】go.Scatterのグラフの描き方まとめ

これからPloltyで動くグラフを作りたい、もっとグラフをキ ...

続きを見る

一方でgo.Scatterglでは単にtext=yとするとプロット点には表示されずホバーに表示される。プロット点に表示させるためにはlistにするか各要素を文字列(string)にする必要がある。試した内容を以下に示す。

np.roundnumpy配列の各要素を四捨五入する関数で、そのまま使用すると桁数が多くなるので四捨五入した。

  • text=y:プロットには表示されずホバーに表示される
  • text=f"{y}":配列全体が表示される
  • text=np.round(y, 2):プロットには表示されずホバーに表示される
  • text=y.tolist():プロットに表示される
  • text=np.round(y, 2).tolist():プロットに表示される
  • text=np.round(y, 2).astype(str):プロットに表示される

上のグラフは.astypeを使用した場合のグラフ。各プロット点にその点のyの値が四捨五入して表示されている。

go.Scattergltextを使用することは少ないだろうが、go.Scatterと挙動が異なるので紹介しておく。

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

# mode='markers+text'でグラフ化

num = 10000
np.random.seed(1)
x = np.random.randn(num)
y = np.random.randn(num)

plot = [
    go.Scattergl(
        x=x, y=y, mode='markers+text',
        marker=dict(color=y, colorscale='jet'),
        # text=y  # プロットには表示されずホバーに表示される
        # text=f"{y}"  # 配列全体が表示される
        # text=np.round(y, 2),  # プロットには表示されずホバーに表示される
        # text=y.tolist(),  # プロットに表示される
        # text=np.round(y, 2).tolist(),  # プロットに表示される
        text=np.round(y, 2).astype(str),  # プロットに表示される
    )
]

layout = go.Layout(title='Scattergl')
fig = go.Figure(data=plot, layout=layout)
# グラフ全体とホバーのフォントサイズ変更
fig.update_layout(font_size=20, hoverlabel_font_size=20)
fig.show()

# グラフ保存
prefix = 'go-scattergl'  # 保存ファイル名の接頭辞
save_name = f"{prefix}_scattergl_text_{num}"
pio.orca.config.executable = '/Applications/orca.app/Contents/MacOS/orca'
pio.write_html(fig, f"{save_name}.html")
pio.write_image(fig, f"{save_name}.png")

ScatterglScatterの描画速度を比較

描画処理のみ グラフ表示のみ グラフ保存のみ グラフ表示後に保存
回数 Scattergl Scatter Scattergl Scatter Scattergl Scatter Scattergl Scatter
1 0.307774 0.32089488 1.677471 2.18238825 14.4267231 31.0453515 15.77174 31.7769413
2 0.31865 0.33095667 2.535154 3.35514833 29.1333956 66.1240122 33.72014 63.826073
3 0.327651 0.34137896 3.639962 4.520175 42.0895075 99.0547675 49.40739 93.0411114
4 0.336292 0.35187017 4.63847 5.869156 55.382133 131.53646 64.5005 124.074986
5 0.346516 0.36271729 5.578106 8.00801662 69.3545265 159.908457 79.13958 157.548764
6 0.356704 0.37197 6.517531 10.083821 84.4228483 188.999129 93.21975 188.945668
7 0.369706 0.38283708 7.533555 13.4813174 100.675488 224.305383 108.5783 219.811906
8 0.380136 0.39143146 8.49465 18.9919425 116.801716 254.365836 122.4507 252.816432
9 0.388507 0.39984108 9.499124 28.7700106 134.09169 284.401813 137.7134 286.390838
10 0.397073 0.40892542 10.48082 36.375247 147.310917 316.606768 154.3879 317.16722

最後にScatterScatterglで処理・描画・保存の速度を比較してみる。今回は以下の4パターンでScatterScatterglの処理終了までの時間を計測した。

グラフ保存で保存の許可を求められた際には放置し、自然に許可されるようにした。手動で許可してしまうと反応タイミングで時間の差異が生まれてしまうという判断だ。

  • グラフを描画のみ(fig=まで)
  • グラフ保存のみ
  • グラフ表示のみ
  • グラフ表示後に保存

使用したコードは以下。それぞれ20万データの散布図を10回ループさせてみた。この検証以外にも色々な方法があると思うが、今回は簡単にこれで進める。なお、go.Scatter版は最後にも載せるが、以下のコードのglがない版だ。

また、グラフ描画のみの場合などグラフ表示処理が不要な時はその部分のコードは削除して実行した。

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

# グラフの描画時間を比較
start_time = time.perf_counter()

# Scatterglでグラフの描画と表示の時間を測定
time_lst = []
for loop in range(10):
    num = 200000  # 20万データ
    np.random.seed(loop)
    x = np.random.randn(num)
    y = np.random.randn(num)

    plot = [
        go.Scattergl(
            x=x, y=y, mode='markers',
            marker=dict(color=y, colorscale='jet'),
        )
    ]

    fig = go.Figure(data=plot)
    fig.show()  # 描画処理のみ・保存のみの場合は不使用

    # グラフ保存。描画処理のみ・グラフ表示のみの場合は不使用
    prefix = './scattergl/go-scattergl'  # 保存ファイル名の接頭辞
    save_name = f"{prefix}_{loop}"
    pio.orca.config.executable = '/Applications/orca.app/Contents/MacOS/orca'
    pio.write_html(fig, f"{save_name}.html")
    pio.write_image(fig, f"{save_name}.png")

    # 作成したグラフにHTMLコードを保存
    html_code = fig.to_html(include_plotlyjs='cdn', full_html=False)
    with open(f"{save_name}.txt", mode='w') as f:
        f.write(html_code)

    execution_time = time.perf_counter() - start_time
    time_lst.append(execution_time)

print(time_lst)

4パターンでgo.Scattergo.Scatterglの処理時間を比較した表がこの章の最初のに示したものだ。単位は秒。描画処理のみの場合は実行時間にそこまでの差は生まれなかったが、グラフ表示と保存処理が加わるとその違いは顕著に現れた。

今回は20万データの10ループだが、グラフ表示後に保存する処理では2倍程度の差が生まれた。なのでやはり大量のデータを扱う際にはgo.Scatterglを使用するのがよさそうだ。

Scatterglなら大量データでも簡単にグラフ化できる

今回はPythonのPlotlyで大量のデータを軽く簡単に扱えるgo.Scatterglを紹介した。WebGL方式で大量のデータでもほとんど引っ掛かりなく動作することができる。

Pytthonはデータ解析やグラフ化が得意なので多くのデータを扱うだろうが、その視覚化に適しているだろう。

ただし、少ないデータの場合は通常のgo.Scatterを使う方が他の人が見ても理解しやすい。go.Scatter以下の記事で解説している。

【Plotlyで散布図】go.Scatterのグラフの描き方まとめ

これからPloltyで動くグラフを作りたい、もっとグラフをキ ...

続きを見る

一方でgo.Scatterglを使う場合は以下と考えている。参考にしていただきたい。

go.Scatterglを使うタイミングの目安

  • 10,000データを超えるグラフ
  • グラフの動きがモッサリしてきた
  • 見栄えより動作が重要

これまで大量のデータを扱う際にデータの重さで悩んでいた人は是非go.Scatterglを使ってほしい。

関連記事

【Plotly&ボタン】updatemenusとbuttonsでボタン機能を追加

Plotlyはプロットしたデータを動かすことができるのが大き ...

続きを見る

【Plotly&ボタン】updatemenusのargs2で2回目のボタン押下機能を追加

今回はPlotlyのボタン機能に2回目のボタン押下の処理を追加& ...

続きを見る

【Plotly&sliders】スライダーを追加しデータを切り変える

本記事ではPlotlyでデータの流れを簡単に理解できる機能の ...

続きを見る

Pythonを効率的に学びたいなら

本記事を読んでもっとPythonを学びたいと思った人もいるだろう。ただ、どうせ学ぶなら効率的に学びたい。

就職するにも転職するにも教養として身に付けたいにしろ、遠回りして学習するのはもったいない。

独学でもなんとかなるが

正直、Pythonの学習は独学でもある程度なんとかなると思う。というより他の言語も独学でなんとかなるのが現実。ただ、なんとかなるとしても以下の問題は見逃せない。

  • プログラミングをやらなくても正直問題ない
  • 何をしたらいいのかわからない
  • どう学習したらいいのかわからない
  • これで合っているのかわからない
  • 時間が足りない

私は大学・大学院の研究でPythonを使用、この時に教えてくれる人がいなかったので独学でPythonを学んで大学院の修士論文が通った。

ただ、あくまでもそれは、

  • 大学の研究の過程で必要
  • 何をしないといけないか明白
  • 大学の研究室が超ホワイト
  • 大学生だから時間があった

という「学生」という身分だから独学で学べただけ。すでに社会人の人は時間がないからかなりキツい。

さらに現在大学生の人も大学の授業や研究室が忙くてなかなか独学が難しいという人もいる。

特に社会人は難しい

以下の記事でも解説したが、特に社会人は日々の仕事に追われプライベートが疎かになりがちだ。そこでさらにプログラミングを学ぼうとするとかなりハードルが高い。

今の生活を振り返って自力で独学で学ぶ覚悟と根気と時間があるか確認してほしい。

【Pythonを独学】社会人が1人で学習できるのか。結論、学べるが...

今回は社会人がプログラミング言語「Python」を独学で学習 ...

続きを見る

スクールだと目的と目標がはっきりする

また、プログラミングを学習したいけど何をしたらいいのかわからない、どうしたらいいのかわからないという漠然とした不安がある人も多いだろう。

そんな人はプログラミングスクールに通うことをおすすめする。スクールだと、

  • 何をすればいいのかわかる
  • したいことがなくてもアドバイスをもらえる
  • 学習方法を教えてもらえる

といったメリットがある。何をするかが分かれば最初の一歩は踏み出しやすい。最初が踏み出せないから今立ち止まっているのだから。

さらに独学とは違いそれなりに費用がかかるので、サボるとかなりもったいない。

スクールで客観的視点を持つ

また、現役でエンジニアとして働く私からいうと、独学で学んだコードは我流で実務では使いづらいことも多い。

このサイトで紹介するコードはあくまでも最初の学習をメインとしているから簡素にしているが、実務ではしっかりと汎用性や保守性を担保しないといけない。

そんな中で独学で突っ走ると転職するにも就職するにもその後がかなりしんどい。

プログラミング学習のショートカットはスクール

結論、独学でPythonを学ぶことは可能。しかし効率的かつ汎用的なスキルを身に付けたいならスクールに通うのが1番だ。特に未経験者はなおさら。

私はプログラミング経験があることで転職で若手なのに年収が数十万円も増えたしプログラミングの知識があることで周りから一目置かれることも。

Pythonに限らずだがプログラミングに興味があれば是非ともトライしていただきたい。

  • この記事を書いた人
  • 最新記事

メガネ

ベンチャー企業のWebエンジニア駆け出し。独学のPythonで天文学系の大学院を修了→転職→今に至る。最近は主にPHPを触ってます。 メインのブログは「M天パ」https://megatenpa.com/です。

-go(plotly.graph_objects), plotly
-, , ,