Pythonで安定的にリアルタイムプロットを実現するライブラリとしては PyQtGraph がありますが、手軽にmatplotlibでプロットしたいことも割とあります。
Web上の様々な記事でmatplotlibはリアルタイムプロットに不向きだと言われていますが、実際にどの程度までリアルタイムプロットができるか調査してみました。
今回の調査では、pyplot.plot()
とpyplot.imshow()
に対して、サイズの異なるデータを与えて平均FPS等を算出してみました。
注意として、matplotlibのリアルタイムプロットは他の動作中アプリケーション
のCPU使用率の影響を受けやすい印象です。
個人的には、結果で30FPS出てたとしても、現実的には10~20FPS程度で降ってくる条件での利用がよいと思っています。
また、PCスペックやOSによっても変わる可能性があります。
検証環境
pyplot.plot()
のFPS測定結果
pyplot.imshow()
データサイズが大きい為、要素数が1万を超えたあたりがら30FPSが厳しくなるのではないかと推測できます。
動画
検証用コード
注意点として、fig.canvas.draw()
やfig.canvas.flush_events()
を呼ぶと結構遅くなります。
"""
License: MIT
Created by Kurene@wizard-notes.com
"""
import time
import numpy as np
import matplotlib.pyplot as plt
def rtplot_line(n_limit, n_dim):
times = np.zeros(n_limit)
fig, ax = plt.subplots()
lines = ax.plot(np.zeros(n_dim))
ax.set_ylim(-3, 3)
pretime = time.time()
count = 0
fps = 1.0
while count < n_limit:
lines[0].set_ydata(np.random.normal(0, 1.0, n_dim))
plt.title(f"fps: {fps:0.1f} Hz, n_dim:{n_dim}, {count:3d}/{n_limit}")
plt.pause(0.001)
curtime = time.time()
times[count] = curtime - pretime
fps = 1.0/times[count]
pretime = curtime
count += 1
plt.close()
return times
def rtplot_imshow(n_limit, n_dim):
times = np.zeros(n_limit)
fig, ax = plt.subplots()
image = ax.imshow(np.random.normal(0, 1.0, (n_dim, n_dim)))
pretime = time.time()
count = 0
fps = 1.0
while count < n_limit:
image.set_data(np.random.normal(0, 1.0, (n_dim, n_dim)))
plt.title(f"fps: {fps:0.1f} Hz, n_dim:{n_dim}, {count:3d}/{n_limit}")
plt.pause(0.001)
curtime = time.time()
times[count] = curtime - pretime
fps = 1.0/times[count]
pretime = curtime
count += 1
plt.close()
return times
targets = [
{"n_dim": 8, "func": rtplot_imshow, "name": "rtplot_imshow"},
{"n_dim": 32, "func": rtplot_imshow, "name": "rtplot_imshow"},
{"n_dim": 128, "func": rtplot_imshow, "name": "rtplot_imshow"},
{"n_dim": 512, "func": rtplot_imshow, "name": "rtplot_imshow"},
{"n_dim": 1024, "func": rtplot_imshow, "name": "rtplot_imshow"},
{"n_dim": 32, "func": rtplot_line, "name": "rtplot_line"},
{"n_dim": 128, "func": rtplot_line, "name": "rtplot_line"},
{"n_dim": 512, "func": rtplot_line, "name": "rtplot_line"},
{"n_dim": 1024, "func": rtplot_line, "name": "rtplot_line"},
{"n_dim": 2048, "func": rtplot_line, "name": "rtplot_line"},
{"n_dim": 4096, "func": rtplot_line, "name": "rtplot_line"},
]
n_limit = 100
for target in targets:
times = target["func"](n_limit, target["n_dim"])
print(f"{target['name']} n_dim:{target['n_dim']}\tfps mean:{1.0/np.mean(times):0.1f}\tmean:{np.mean(times):0.3f}\tstd:{np.std(times):0.3f}")
参考文献