Matplotlib は、Python と NumPy のためのプロットライブラリです。Tkinter、wxPython、Qt、GTK のような汎用 GUI ツールキットを使ったアプリケーションにプロットを埋め込むためのオブジェクト指向 API を提供しています。
Matplotlib で時系列データを扱うとき、ある時間間隔でデータ点を追加してチャートに反映させたい場合があります。
Matplotlib のチャート作成速度は十分高速ですので、単純なトレンドチャートであれば、一旦チャートを消去して新たなデータが追加されたデータセットで描画し直しても、十分実用レベルで利用できます。しかし、このようにチャートを書き直す方法は、プログラミング的には無駄に計算リソースを食い潰しているようで好きではありません。
トレンドチャートでデータ点を追加するのにもう少しスマートな方法がないか探していたところ、参考サイト [1] に、トレンド線の matplotlib.lines.Line2D オブジェクトのデータを更新して描画し直す方法が紹介されていました。この方法でも結局のところ新しく線を引き直しているのですが、それでもチャート全体を描画し直すよりはマシです。
参考サイト [1] で紹介されていたサンプルは、自分がやりたいこととは少々違っていましたので、紹介されていたサンプルを元にして直感的に判りやすいと思われるサンプルを作りました。
- Matplotlib の plot によるトレンドチャートで、データ点を逐次追加したい。
下記の OS 環境で動作確認をしています。
![]() |
RHEL 9.4 | x86_64 |
Python | 3.12.1 | |
matplotlib | 3.9.0 |
サンプルを以下に示しました。
# Reference: | |
# https://stackoverflow.com/questions/58186783/updating-matplotlib-figures-in-real-time-for-data-acquisition | |
import matplotlib.pyplot as plt | |
import numpy | |
if __name__ == '__main__': | |
x_max = 500 | |
fig = plt.figure() | |
ax = fig.gca() | |
ax.set_xlim(0, x_max) | |
ax.set_ylim(-1, 1) | |
plt.grid() | |
line, = plt.plot([], [], label='TEST') | |
ax.legend(loc='best') | |
for i in range(x_max): | |
x = float(i) | |
y = numpy.sin(x * 0.1) | |
line.set_xdata(numpy.append(line.get_xdata(), [x])) | |
line.set_ydata(numpy.append(line.get_ydata(), [y])) | |
fig.canvas.draw_idle() | |
fig.canvas.flush_events() | |
# adjust pause duration here | |
plt.pause(0.01) | |
print("DONE") | |
plt.show() |
サンプルの実行例を以下に示しました。
サンプルの説明
まず、matplotlib.pyplot.plot で空のチャートを作成します。凡例用の文字列を 'TEST' としました。
plot の返り値は matplotlib.lines.Line2D のリストですので、その最初の要素(オブジェクト)を line として保持します。
line, = plt.plot([], [], label = 'TEST' ) |
データを逐次追加するデモのため、ここでは、500 回のループを実行しています。ループの内容は次のとおりです。
新しいデータ点 (x, y) を生成します(デモ用に正弦関数を使っています)。
この新たなデータ点を追加する際、現行の x, y データ列を line オブジェクトの get_xdata、get_ydata メソッドで取り出し、新たな x, y データを追加して set_xdata、set_ydata メソッドで設定し直します。
line.set_xdata(numpy.append(line.get_xdata(), [x])) line.set_ydata(numpy.append(line.get_ydata(), [y])) fig.canvas.draw_idle() fig.canvas.flush_events() |
最後の二行は使用経験が浅く、詳しく説明できないので、マニュアルから抜き出した説明だけです。
- fig.canvas.draw_idle() は、制御が GUI のイベントループに戻ったら、ウィジェットの再描画を要求します。
- fig.canvas.flush_events() は、GUI のイベントをフラッシュ(消去)します。
最後に matplotlib.pyplot.pause で 0.01 秒のイベントループを実行します。
plt.pause( 0.01 ) |
違うサンプルをもう少し作って、使い方を咀嚼できたら、次のステップとして PySide6 の GUI に組み込んでみます。
参考サイト
- python - Updating matplotlib figures in real time for data acquisition - Stack Overflow [2019-10-01]
- matplotlib.pyplot.plot — Matplotlib documentation
- matplotlib.lines.Line2D — Matplotlib documentation
- matplotlib.backend_bases — Matplotlib documentation
- matplotlib.pyplot.pause — Matplotlib documentation

にほんブログ村
#オープンソース

0 件のコメント:
コメントを投稿