2013-06-14 18 views
9

Đối với bộ phân tích dữ liệu điện sinh lý, tôi cần vẽ một mảng 2D lớn (khoảng 20.000 x 120) điểm. Tôi sử dụng để nhúng một widget Matplotlib trong ứng dụng PyQt của tôi, nhưng đã đi tìm các giải pháp khác bởi vì âm mưu diễn ra khá lâu. Tuy nhiên, vẽ sơ đồ dữ liệu bằng pyqtgraph cũng mất nhiều thời gian hơn dự kiến, có lẽ vì nó vẽ lại widget mỗi khi sử dụng hàm plot().Vẽ các mảng lớn trong pyqtgraph

Phương pháp hay nhất để vẽ các mảng lớn là gì?

Các ví dụ pyqtgraph, mặc dù rộng lớn, không giúp tôi nhiều hơn nữa ...

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

for n in data: 
    w1.plot(n) 

hoặc

w1.plot(data) 

Nguyên tắc cuối cùng tạo ra ValueError: toán hạng không thể được phát sóng cùng có hình dạng (10) (10,120)

Cảm ơn trước ....

+0

Bạn nghĩ thời gian "khá dài" trong bao lâu? Tôi dễ dàng vẽ 20.000 x 120 điểm trong một giây. Đối với một ảnh chụp đó không phải là một vấn đề. Ví dụ, tôi muốn hiển thị một ECG sống 128-dẫn, nó là không đủ. – Micke

+0

Ngay cả khi tôi giảm dữ liệu xuống 200x120 điểm, nó mất 6 giây. Bạn có sử dụng cùng một mã không? –

+0

Cho rằng bạn đã không nói với tôi chính xác những gì 'dữ liệu' có vẻ như tôi không chắc chắn. Tôi đã sử dụng mảng numpy.empty ([120, 20000], dtype = numpy.int16). Có thể đăng mã tối nay. – Micke

Trả lời

25

Xem thảo luận này: https://groups.google.com/forum/?fromgroups#!searchin/pyqtgraph/arraytoqpath/pyqtgraph/CBLmhlKWnfo/jinNoI07OqkJ

Pyqtgraph không vẽ lại sau mỗi cuộc gọi để vẽ(); nó sẽ đợi cho đến khi điều khiển trở lại vòng lặp sự kiện Qt trước khi vẽ lại. Tuy nhiên, có thể mã của bạn buộc vòng lặp sự kiện phải được truy cập thường xuyên hơn bằng cách gọi QApplication.processEvents() (điều này có thể xảy ra gián tiếp, ví dụ: nếu bạn có hộp thoại tiến trình).

Nói chung, quy tắc quan trọng nhất về cải thiện hiệu suất là: cấu hình mã của bạn. Đừng đưa ra giả định về những gì có thể làm chậm bạn nếu bạn có thể đo trực tiếp điều đó.

Vì tôi không có quyền truy cập vào mã của bạn, tôi chỉ có thể đoán cách cải thiện mã và hiển thị cho bạn cách hồ sơ có thể trợ giúp. Tôi sẽ bắt đầu với ví dụ 'chậm' ở đây và làm việc thông qua một vài cải tiến.

1. Việc thực hiện chậm

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_() 

Kết quả của việc này là:

Plot time: 6.10 sec 

Bây giờ chúng ta hãy cấu hình nó:

$ 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) 
. . . 

Đã chúng ta có thể thấy rằng ViewBox. updateAutoRange mất nhiều thời gian, vì vậy hãy tắt tính năng tự động:

2. Một chút nhanh hơn

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_() 

..và đầu ra là:

Plot time: 0.68 sec 

Vì vậy, đó là nhanh hơn một chút, nhưng panning/rộng cốt truyện vẫn còn khá chậm.Nếu tôi xem hồ sơ sau khi kéo ô trong một thời gian, có vẻ như sau:

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) 

Vì vậy, chúng tôi thấy nhiều cuộc gọi tới PlotCurveItem.paint(). Điều gì sẽ xảy ra nếu chúng ta đặt tất cả 120 dòng âm mưu vào một mục duy nhất để giảm số lượng cuộc gọi sơn?

3. Việc thực hiện nhanh

Sau một vài vòng hồ sơ, tôi đã đưa ra với điều này. Nó dựa trên việc sử dụng pg.arrayToQPath, như được đề xuất trong chuỗi ở trên:

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_() 

Bắt đầu nhanh và mở rộng/thu nhỏ được đáp ứng hợp lý. Tuy nhiên, tôi sẽ nhấn mạnh rằng liệu giải pháp này có hiệu quả cho bạn hay không, bạn sẽ phụ thuộc vào các chi tiết của chương trình của bạn.

+1

Cảm ơn bạn đã trả lời rộng rãi của mình, tôi sẽ triển khai thuật toán cuối cùng vào chương trình và thử. Là một phần thưởng, tôi đã học được một số điều về cách ứng dụng hồ sơ :) –

+0

Cảm ơn câu trả lời này. Tôi đã cố gắng đọc và vẽ nhiều tập dữ liệu tuần tự trong khoảng thời gian ngắn nhất. Tôi đã thêm một vòng lặp nhỏ bằng cách sử dụng 'lines.setPath' hoạt động tốt. Tuy nhiên, tôi không thể thực hiện lớp 'RemoteGraphicsView' đúng cách để tăng tốc độ vẽ đồ thị. Bạn có thể thêm một ví dụ? – bejota

Các vấn đề liên quan