81
113

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

大容量データもサクサク動くPlotly!「plotly-resampler」で楽々高速化!

Posted at

1. はじめに

Python のプロットツールとして、matplotlib の代わりに、下の図のようなブラウザ上でぐりぐりと操作できる Plotly が便利で使うことが多いのですが、
defo.gif
大容量データを一度にプロットすると、非常に重くなるのが気になっていました。

これまで描画のときだけデータを粗くするなど工夫してきたのですが、毎回大変なので、なにか便利なものはないかなーと探していたら、よいカスタムライブラリを見つけたので、この記事で紹介したいと思います!

2. 通常のプロットサンプル

まず、比較のために、1000万のサンプルデータを作成して、通常の方法で Plotly でプロットしてみます。

コードはこちらです。

import pandas as pd
import numpy as np
from plotly.subplots import make_subplots
import plotly.graph_objects as go

def create_data():
    # データの作成
    x = np.arange(10_000_000)
    noisy_sine = (3 + np.sin(x / 200) + np.random.randn(len(x)) / 10) * x / 1_000
    noisy_cos = (3 + np.cos(x / 200) + np.random.randn(len(x)) / 10) * x / 1_000
    return pd.DataFrame(data={"sine": noisy_sine + 2, "cosine": noisy_cos})

def plot_data(df):
    # サブプロットの作成
    fig = make_subplots(rows=2, cols=1, shared_xaxes=True)
    # 最初のデータセットを追加
    fig.add_trace(go.Scatter(y=df["sine"], name="sine"), row=1, col=1)
    # 2番目のデータセットを追加
    fig.add_trace(go.Scatter(y=df["cosine"], name="cosine"), row=2, col=1)
    fig.update_layout(autosize=False, width=1200, height=600)
    return fig

def main():
    # データの取得
    df = create_data()
    # データのプロット
    fig = plot_data(df)
    # plotを表示する
    fig.show()

これを実行したのが以下の動画になります。
normal_plot6.gif
プログラムを実行してから画面が表示されるまで30秒以上待つ上に、そのあとのズームやパンなどの操作も、画面が固まったり、応答が遅かったり、全体的にもっさりとした感じです。

3. plotly-resampler を使ったサンプル

今度は、同じデータを plotly-resampler を使用してプロットしてみます。
先にライブラリのインストールをお願いします。

pip install plotly-resampler
import pandas as pd
import numpy as np
from plotly.subplots import make_subplots
import plotly.graph_objects as go
from plotly_resampler import register_plotly_resampler
from threading import Timer
import webbrowser

def create_data():
    # データの作成
    x = np.arange(10_000_000)
    noisy_sine = (3 + np.sin(x / 200) + np.random.randn(len(x)) / 10) * x / 1_000
    noisy_cos = (3 + np.cos(x / 200) + np.random.randn(len(x)) / 10) * x / 1_000
    return pd.DataFrame(data={"sine": noisy_sine + 2, "cosine": noisy_cos})

def plot_data(df):
    # サブプロットの作成
    fig = make_subplots(rows=2, cols=1, shared_xaxes=True)
    # 最初のデータセットを追加
    fig.add_trace(go.Scatter(y=df["sine"], name="sine"), row=1, col=1)
    # 2番目のデータセットを追加
    fig.add_trace(go.Scatter(y=df["cosine"], name="cosine"), row=2, col=1)
    fig.update_layout(autosize=False, width=1200, height=600)
    return fig

def open_browser(port):
    # ブラウザを開く(省いてもOK)
    webbrowser.open_new(f"http://localhost:{port}")

def main():
    # resamplerの登録
    register_plotly_resampler(mode='auto')
    # データの取得
    df = create_data()
    # データのプロット
    fig = plot_data(df)
    # 自動的にブラウザを開く(省いてもOK)
    port = 8447
    Timer(1, lambda: open_browser(port)).start()
    # dashにplotを表示する(fig.show()の代わりに使う)
    fig.show_dash(mode='inline', port=port)

if __name__ == "__main__":
    main()

こちらのコードを実行した動画が下記になります。
resample_plot7.gif
プログラムを実行してから画面が表示されるまでの時間が3秒程度と、先ほどの約1/10になり、同じように操作したときの応答も非常にサクサクになりました!

表示範囲に応じてプロット点数が調整されているようで、描画が粗くなっている部分もありますが、素早く目的のデータを見つけて拡大できるようになりました。いいですね!

4. 使い方の補足と注意点

詳しい使い方は、公式リポジトリ に丁寧な説明があります。

  • plotly-resampler の使い方の基本

    plotly の代わりに plotly-resampler を使用したい場合は、以下のコードのように冒頭で register_plotly_resampler(mode='auto') 関数を定義したあと、通常のプロットコードを書いて、最後に fig.show() の代わりに fig.show_dash() でプロットを出力します。

    from plotly_resampler import register_plotly_resampler
    
    # resamplerの登録
    register_plotly_resampler(mode='auto')
    
    # 通常のplotlyのプロットコード
    (省略)
    
    # dashにplotを表示する
    fig.show_dash(mode='inline')
    

    上記例は、自動で plotly-resampler を適用するAutoモードですが、細かくカスタムするために、Manual適用する方法もリポジトリで紹介されています。

plotly-resampler はWebフレームワークの Dash の上で実行されます。大容量データでもサクサク動くかわりに、plotlyのように静的なHTMLとしてブラウザだけで実行して見るということはできなくなります。

  • リポジトリの examples にサンプルコードがたくさんありますが、plotly-resampler はPlotly のすべてのグラフや機能に対応しているわけではないようでした。例えば、(私がPlotlyでよく使う)Range Slider 機能 は対応していませんでした。

  • Plotly をWebフレームワークである Streamlitから使用することが多いのですが、plotly-resampler は Streamlit には公式で対応していません。

    • 一応 こちらの issue に実行方法が書かれていて、実行はできたのですが、ウィジェットとプロットを連動させる方法がよくわかりませんでした。
    • 開発者は Dash の愛好家のようで、Dash の例はたくさんあるので、Webアプリから plotly-resampler を使いたいのなら ChatGPT に手伝ってもらって Dash から使う方が簡単かもしれません。

5. おわりに

どんな状況でも使えるというわけではないですが、サクッと試せるので、同じ悩みを持つ方はぜひ使ってみてください!

81
113
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
81
113

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?