2013-06-14 33 views
9

電気生理学データ解析セットでは、大きな2Dアレイ(約20,000×120点)をプロットする必要があります。 Matplotlibウィジェットを私のPyQtアプリケーションに埋め込んでいましたが、作図にはかなり時間がかかりましたので、他のソリューションを探していました。それでも、pyqtgraphでデータをプロットすることは、おそらくplot()関数を使用するときにウィジェットを再描画するので、予想よりもはるかに時間がかかります。pyqtgraphで大きなアレイをプロットする

大きな配列をプロットするにはどうすればよいですか?オペランド一緒に放送することができませんでした:

pyqtgraph例

、豊富なものの、最後のルールは とValueErrorが発生し...更に多く

import pyqtgraph as pg 
view = pg.GraphicsLayoutWidget() 
w1 = view.addPlot() 

for n in data: 
    w1.plot(n) 

または

w1.plot(data) 

私を助けていません形状(10)(10,120)

ありがとうございました....

+0

「かなり長い」とはどのくらいの時間を考えますか?私は簡単に秒で20.000 x 120点をプロットします。問題ではないスナップショットの場合私はあなたが例えば128リードの生きているECGを見せたいと思っているだけで十分ではありません。 – Micke

+0

データを200x120ポイントに減らしても、6秒かかります。あなたは同じコードを使用していますか? –

+0

「データ」がどのように見えるかを私に正確に教えてくれなかったことを考えればわかりません。 numpy.empty([120、20000]、dtype = numpy.int16)配列を使用しました。今夜コードを投稿できます。 – Micke

答えて

25

この議論を参照してください: https://groups.google.com/forum/?fromgroups#!searchin/pyqtgraph/arraytoqpath/pyqtgraph/CBLmhlKWnfo/jinNoI07OqkJ

Pyqtgraphは(プロットするすべての呼び出し後に再描画されません)。再描画の前にコントロールがQtイベントループに戻るまで待機します。しかし、QApplication.processEvents()を呼び出すことによって、コードがイベントループをより頻繁に訪れるようになる可能性があります(これは、例えば進行状況ダイアログが表示されている間接的に発生する可能性があります)。

一般的に、パフォーマンスを向上させるための最も重要なルールは、profile codeです。代わりに直接測定することができれば、何が減速しているのかを前提にしないでください。

私はあなたのコードにアクセスすることができないので、私はそれを改善し、プロファイリングがどのように役立つかを示すしか方法がないと思います。ここでは「スロー」な例から始め、いくつかの改善を進めていきます。

1.遅い実装

import pyqtgraph as pg 
import numpy as np 
app = pg.mkQApp() 
data = np.random.normal(size=(120,20000), scale=0.2) + \ 
     np.arange(120)[:,np.newaxis] 
view = pg.GraphicsLayoutWidget() 
view.show() 
w1 = view.addPlot() 
now = pg.ptime.time() 
for n in data: 
    w1.plot(n) 
print "Plot time: %0.2f sec" % (pg.ptime.time()-now) 
app.exec_() 

これの出力は次のとおりです。

Plot time: 6.10 sec 

今度はそれをプロファイリングしてみましょう:

$ python -m cProfile -s cumulative speed_test.py 
. . . 
    ncalls tottime percall cumtime percall filename:lineno(function) 
      1 0.001 0.001 11.705 11.705 speed_test.py:1(<module>) 
     120 0.002 0.000 8.973 0.075 PlotItem.py:614(plot) 
     120 0.011 0.000 8.521 0.071 PlotItem.py:500(addItem) 
    363/362 0.030 0.000 7.982 0.022 ViewBox.py:559(updateAutoRange) 
. . . 

すでに我々はそのViewBoxをを見ることができます。 updateAutoRangeには時間がかかりますので、自動レンジングを無効にしましょう:

2.少し速く

import pyqtgraph as pg 
import numpy as np 
app = pg.mkQApp() 
data = np.random.normal(size=(120,20000), scale=0.2) + \ 
     np.arange(120)[:,np.newaxis] 
view = pg.GraphicsLayoutWidget() 
view.show() 
w1 = view.addPlot() 
w1.disableAutoRange() 
now = pg.ptime.time() 
for n in data: 
    w1.plot(n) 
w1.autoRange() # only after plots are added 
print "Plot time: %0.2f sec" % (pg.ptime.time()-now) 
app.exec_() 

..and出力は次のとおりです。

Plot time: 0.68 sec 

は、だからそれは少し速くですが、パン/プロットをスケーリングすることはまだかなり遅いです。私はしばらくの間、プロットをドラッグした後、プロフィールを見れば、それは次のようになります。

ncalls tottime percall cumtime percall filename:lineno(function) 
     1 0.034 0.034 16.627 16.627 speed_test.py:1(<module>) 
     1 1.575 1.575 11.627 11.627 {built-in method exec_} 
     20 0.000 0.000 7.426 0.371 GraphicsView.py:147(paintEvent) 
     20 0.124 0.006 7.425 0.371 {paintEvent} 
    2145 0.076 0.000 6.996 0.003 PlotCurveItem.py:369(paint) 

だから我々は(PlotCurveItem.paintへの呼び出しの多くを参照してください)。ペイントコールの回数を減らすために、120個のプロットラインをすべて1つのアイテムにまとめるとどうなりますか?プロファイリングのカップルのラウンド後

3.高速な実装

、私はこれを思い付きました。上記のスレッドで提案されているようにpg.arrayToQPathの使用に基づいています:

import pyqtgraph as pg 
import numpy as np 
app = pg.mkQApp() 

y = np.random.normal(size=(120,20000), scale=0.2) + np.arange(120)[:,np.newaxis] 
x = np.empty((120,20000)) 
x[:] = np.arange(20000)[np.newaxis,:] 
view = pg.GraphicsLayoutWidget() 
view.show() 
w1 = view.addPlot() 

class MultiLine(pg.QtGui.QGraphicsPathItem): 
    def __init__(self, x, y): 
     """x and y are 2D arrays of shape (Nplots, Nsamples)""" 
     connect = np.ones(x.shape, dtype=bool) 
     connect[:,-1] = 0 # don't draw the segment between each trace 
     self.path = pg.arrayToQPath(x.flatten(), y.flatten(), connect.flatten()) 
     pg.QtGui.QGraphicsPathItem.__init__(self, self.path) 
     self.setPen(pg.mkPen('w')) 
    def shape(self): # override because QGraphicsPathItem.shape is too expensive. 
     return pg.QtGui.QGraphicsItem.shape(self) 
    def boundingRect(self): 
     return self.path.boundingRect() 

now = pg.ptime.time() 
lines = MultiLine(x, y) 
w1.addItem(lines) 
print "Plot time: %0.2f sec" % (pg.ptime.time()-now) 

app.exec_() 

それがすぐに開始され、パン/スケーリングが合理的に応答します。しかし、このソリューションがあなたのために機能するかどうかは、プログラムの詳細に依存する可能性が高いことを強調します。

+1

広範な答えをありがとう、私はプログラムに最後のアルゴリズムを実装し、それを試してみましょう。ボーナスとして、アプリのプロファイリングについても学びました:) –

+0

この回答に感謝します。私は、最短時間で複数のデータセットを連続して読み書きしようとしています。私は 'lines.setPath'を使って簡単なループを追加しました。これはうまくいきます。しかし、プロットをさらに高速化するために、 'RemoteGraphicsView'クラスを適切に実装することはできません。例を追加できますか? – bejota

関連する問題