wxPythonを使用する「本番」アプリケーションで、matplotlibでデータのリアルタイムプロットを実行しようとしています。私はこの目的でChacoを使用していましたが、将来的にはさまざまな理由でChacoを避けようとしています。その理由のひとつは、十分に文書化されていないため、必要なときにChacoのソースコードを読むのに長い時間を費やさなければならないことです。最小の機能でさえ私のプロットの1つに追加します。Chacoがmatplotlibに勝つ1つの側面は速度にあるので、私はmatplotlibから許容できるパフォーマンスを得る方法を模索しています。
matplotlibの高速プロットで広く使用されている手法の1つは、頻繁に更新するプロットの要素に設定animated
しTrue
、背景(軸、目盛りなど)を1回だけ描画し、そのcanvas.copy_from_bbox()
方法を使用して次のことを行うことです。背景を保存します。次に、新しいforeground
(プロットトレースなど)を描画するときにcanvas.restore_region()
、事前にレンダリングされた背景を画面にコピーしてから、新しい前景axis.draw_artist()
とcanvas.blit()
それを画面に描画するために使用します。
FigureCanvasWxAggをwxPythonフレームに埋め込み、ランダムデータの単一のトレースを45FPSで表示しようとする非常に単純な例を作成しました。プログラムがデフォルトサイズ(ソースにハードコードされている)のフレームで実行されている場合、私のマシンでは1秒あたり最大13〜14フレームを達成します。ウィンドウを最大化すると、更新は約5.5FPSに低下します。特に、リアルタイムでレンダリングする要素を追加し始めたら、これは私のアプリケーションにとって十分な速度ではないと思います。
私のコードはここに投稿されています:basic_fastplot.py
これをもっと速くできるかどうか疑問に思ったので、コードのプロファイルを作成したところ、処理時間の最大の消費者はcanvas.blit()
99行目と109行目の呼び出しであることがわかりました。この時間のは、への特定の呼び出しに費やされMemoryDC.SelectObject()
ます。周囲のコードにはいくつかの呼び出しがありますがSelectObject
、以下にマークされているものだけがかなりの時間を要します。
matplotlibソースから、backend_wxagg.py:
class FigureCanvasWxAgg(FigureCanvasAgg, FigureCanvasWx):
# ...
def blit(self, bbox=None):
"""
Transfer the region of the agg buffer defined by bbox to the display.
If bbox is None, the entire buffer is transferred.
"""
if bbox is None:
self.bitmap = _convert_agg_to_wx_bitmap(self.get_renderer(), None)
self.gui_repaint()
return
l, b, w, h = bbox.bounds
r = l + w
t = b + h
x = int(l)
y = int(self.bitmap.GetHeight() - t)
srcBmp = _convert_agg_to_wx_bitmap(self.get_renderer(), None)
srcDC = wx.MemoryDC()
srcDC.SelectObject(srcBmp) # <<<< Most time is spent here, 30milliseconds or more!
destDC = wx.MemoryDC()
destDC.SelectObject(self.bitmap)
destDC.BeginDrawing()
destDC.Blit(x, y, int(w), int(h), srcDC, x, y)
destDC.EndDrawing()
destDC.SelectObject(wx.NullBitmap)
srcDC.SelectObject(wx.NullBitmap)
self.gui_repaint()
私の質問:
- SelectObject()は、これほど時間がかかっていることを何をしているのでしょうか。ポインタなどを設定するだけで、コピーや計算はあまり行わないと思っていました。
- これを高速化できる方法はありますか(フルスクリーンで10 FPSを取得するため)?