2012-01-21 37 views
65

Tôi hiện đang đánh giá các thư viện vẽ sơ đồ python khác nhau. Ngay bây giờ tôi đang cố gắng matplotlib và tôi khá thất vọng với hiệu suất. Ví dụ sau được sửa đổi từ SciPy examples và chỉ cho tôi ~ 8 khung hình mỗi giây!tại sao âm mưu với Matplotlib quá chậm?

Bất kỳ cách nào để tăng tốc độ này hoặc tôi có nên chọn một thư viện vẽ khác không?

from pylab import * 
import time 

ion() 
fig = figure() 
ax1 = fig.add_subplot(611) 
ax2 = fig.add_subplot(612) 
ax3 = fig.add_subplot(613) 
ax4 = fig.add_subplot(614) 
ax5 = fig.add_subplot(615) 
ax6 = fig.add_subplot(616) 

x = arange(0,2*pi,0.01) 
y = sin(x) 
line1, = ax1.plot(x, y, 'r-') 
line2, = ax2.plot(x, y, 'g-') 
line3, = ax3.plot(x, y, 'y-') 
line4, = ax4.plot(x, y, 'm-') 
line5, = ax5.plot(x, y, 'k-') 
line6, = ax6.plot(x, y, 'p-') 

# turn off interactive plotting - speeds things up by 1 Frame/second 
plt.ioff() 


tstart = time.time()    # for profiling 
for i in arange(1, 200): 
    line1.set_ydata(sin(x+i/10.0)) # update the data 
    line2.set_ydata(sin(2*x+i/10.0)) 
    line3.set_ydata(sin(3*x+i/10.0)) 
    line4.set_ydata(sin(4*x+i/10.0)) 
    line5.set_ydata(sin(5*x+i/10.0)) 
    line6.set_ydata(sin(6*x+i/10.0)) 
    draw()       # redraw the canvas 

print 'FPS:' , 200/(time.time()-tstart) 
+0

Sau đây có thể có liên quan: http://stackoverflow.com/questions/5003094/how-can-i-speed-up-an-animation – NPE

+2

@aix - Glumpy chỉ giúp trong ví dụ đó bởi vì anh ta đang xử lý hình ảnh hiển thị nhanh chóng dữ liệu. Nó sẽ không giúp đỡ trong trường hợp này. –

+1

Thử thay đổi chương trình phụ trợ. Xem câu trả lời của tôi: http://stackoverflow.com/a/30655528/2066079. hoặc Câu hỏi thường gặp này về các chương trình phụ trợ: http://matplotlib.org/faq/usage_faq.html#what-is-a-backend – dberm22

Trả lời

85

Trước hết, (mặc dù điều này sẽ không thay đổi việc thực hiện tại tất cả) xem xét việc dọn dẹp mã của bạn, tương tự như sau:

import matplotlib.pyplot as plt 
import numpy as np 
import time 

x = np.arange(0, 2*np.pi, 0.01) 
y = np.sin(x) 

fig, axes = plt.subplots(nrows=6) 
styles = ['r-', 'g-', 'y-', 'm-', 'k-', 'c-'] 
lines = [ax.plot(x, y, style)[0] for ax, style in zip(axes, styles)] 

fig.show() 

tstart = time.time() 
for i in xrange(1, 20): 
    for j, line in enumerate(lines, start=1): 
     line.set_ydata(np.sin(j*x + i/10.0)) 
    fig.canvas.draw() 

print 'FPS:' , 20/(time.time()-tstart) 

Với ví dụ trên, tôi nhận được khoảng 10fps.

Chỉ cần lưu ý nhanh, tùy thuộc vào trường hợp sử dụng chính xác của bạn, matplotlib có thể không phải là lựa chọn tuyệt vời. Nó hướng tới các con số chất lượng xuất bản, chứ không phải hiển thị thời gian thực.

Tuy nhiên, có rất nhiều việc bạn có thể làm để tăng tốc ví dụ này.

Có hai lý do chính tại sao điều này chậm như hiện tại.

1) Gọi fig.canvas.draw() vẽ lại mọi thứ. Đó là nút cổ chai của bạn. Trong trường hợp của bạn, bạn không cần phải vẽ lại những thứ như ranh giới rìu, đánh dấu nhãn, v.v.

2) Trong trường hợp của bạn, có rất nhiều điểm con có nhiều nhãn đánh dấu. Chúng mất một thời gian dài để vẽ.

Cả hai điều này có thể được khắc phục bằng cách sử dụng tính năng nhòe.

Để thực hiện đánh dấu hiệu quả, bạn sẽ phải sử dụng mã phụ trợ cụ thể. Trong thực tế, nếu bạn đang thực sự lo lắng về hình ảnh động trơn tru, bạn thường nhúng matplotlib lô trong một số loại bộ công cụ gui, anyway, vì vậy đây không phải là một vấn đề.

Tuy nhiên, không biết nhiều hơn về những gì bạn đang làm, tôi không thể giúp bạn ở đó.

Tuy nhiên, có một cách gui-trung lập để làm điều đó vẫn còn khá nhanh.

import matplotlib.pyplot as plt 
import numpy as np 
import time 

x = np.arange(0, 2*np.pi, 0.1) 
y = np.sin(x) 

fig, axes = plt.subplots(nrows=6) 

fig.show() 

# We need to draw the canvas before we start animating... 
fig.canvas.draw() 

styles = ['r-', 'g-', 'y-', 'm-', 'k-', 'c-'] 
def plot(ax, style): 
    return ax.plot(x, y, style, animated=True)[0] 
lines = [plot(ax, style) for ax, style in zip(axes, styles)] 

# Let's capture the background of the figure 
backgrounds = [fig.canvas.copy_from_bbox(ax.bbox) for ax in axes] 

tstart = time.time() 
for i in xrange(1, 2000): 
    items = enumerate(zip(lines, axes, backgrounds), start=1) 
    for j, (line, ax, background) in items: 
     fig.canvas.restore_region(background) 
     line.set_ydata(np.sin(j*x + i/10.0)) 
     ax.draw_artist(line) 
     fig.canvas.blit(ax.bbox) 

print 'FPS:' , 2000/(time.time()-tstart) 

Điều này mang lại cho tôi ~ 200 khung hình/giây.

Để làm điều này thuận tiện hơn một chút, có mô-đun animations trong các phiên bản gần đây của matplotlib.

Như một ví dụ:

import matplotlib.pyplot as plt 
import matplotlib.animation as animation 
import numpy as np 

x = np.arange(0, 2*np.pi, 0.1) 
y = np.sin(x) 

fig, axes = plt.subplots(nrows=6) 

styles = ['r-', 'g-', 'y-', 'm-', 'k-', 'c-'] 
def plot(ax, style): 
    return ax.plot(x, y, style, animated=True)[0] 
lines = [plot(ax, style) for ax, style in zip(axes, styles)] 

def animate(i): 
    for j, line in enumerate(lines, start=1): 
     line.set_ydata(np.sin(j*x + i/10.0)) 
    return lines 

# We'd normally specify a reasonable "interval" here... 
ani = animation.FuncAnimation(fig, animate, xrange(1, 200), 
           interval=0, blit=True) 
plt.show() 
+0

mã của bạn rất nhanh, tuy nhiên, tôi kết thúc với 2000 dòng trên mỗi trục! bằng cách nào đó "line.set_ydata" tạo ra một dòng mới thay vì cập nhật nó - hoặc là nền không bị xóa? Ngoài ra, tại sao phiên bản của bạn nhanh hơn rất nhiều? chỉ vì bạn đã bỏ "draw()" và thay thế nó bằng "ax.draw_artist"? – memyself

+0

Trong ví dụ nào? (Tôi đã thử nghiệm chúng, nhưng có thể sao chép phiên bản sai vào câu trả lời.) Ngoài ra, bạn đang sử dụng phiên bản matplotlib nào? –

+0

Tôi có nghĩa là ví dụ thứ hai. Tôi sử dụng matplotlib phiên bản 1.0.1. – memyself

12

Matplotlib làm đồ họa ấn phẩm có chất lượng tuyệt vời, nhưng không phải là rất tốt tối ưu hóa cho tốc độ. Có rất nhiều các gói python âm mưu được thiết kế với tốc độ trong tâm trí:

4

Đối với giải pháp đầu tiên bởi Joe Kington (.copy_from_bbox & .draw_artist & canvas.blit) đề xuất, tôi phải nắm bắt được nền sau dòng fig.canvas.draw(), nếu không nền không có hiệu lực và tôi nhận được kết quả tương tự như bạn đã đề cập. Nếu bạn đặt nó sau fig.show() nó vẫn không hoạt động như được đề xuất bởi Michael Browne.

Vì vậy, chỉ cần đặt dòng nền sau các canvas.draw():

[...] 
fig.show() 

# We need to draw the canvas before we start animating... 
fig.canvas.draw() 

# Let's capture the background of the figure 
backgrounds = [fig.canvas.copy_from_bbox(ax.bbox) for ax in axes] 
+3

bạn chỉ nên chỉnh sửa câu trả lời của mình thay vì đăng bài dưới dạng riêng biệt – endolith

9

Để bắt đầu, Joe Kington's answer đưa ra lời khuyên rất tốt sử dụng một cách tiếp cận gui-trung tính, và bạn chắc chắn nên mình lời khuyên (đặc biệt là về Blitting) và đưa nó vào thực tế. Thông tin thêm về phương pháp này, hãy đọc cách tiếp cận Matplotlib Cookbook

Tuy nhiên, cách tiếp cận không có GUI-trung lập (GUI-biased?) Là chìa khóa để tăng tốc âm mưu. Nói cách khác, các backend là cực kỳ quan trọng để âm mưu tốc độ.

Đặt hai dòng sau trước khi bạn nhập bất cứ thứ gì từ matplotlib:

import matplotlib 
matplotlib.use('GTKAgg') 

Tất nhiên, có những lựa chọn khác nhau để sử dụng thay vì GTKAgg, nhưng theo sách dạy nấu ăn đã đề cập trước, đây là nhanh nhất. Xem liên kết về các chương trình phụ trợ để có thêm tùy chọn.

+0

Tính năng này chỉ hoạt động trên các cửa sổ, bạn có biết cách làm cho nó hoạt động trên Mac hay không. Lý do nó là cửa sổ cụ thể là pygtk là cửa sổ cụ thể – user308827

+1

pygtk không phải là cửa sổ cụ thể. Trong thực tế, đó là một nỗi đau lớn nhận được nó làm việc trong Windows (nếu nó thậm chí có thể, tôi đã từ bỏ.) –

1

Điều này có thể không áp dụng cho nhiều bạn, nhưng tôi thường điều hành máy tính của mình dưới Linux, vì vậy theo mặc định, tôi lưu các ô matplotlib của tôi dưới dạng PNG và SVG. Điều này hoạt động tốt dưới Linux nhưng không thể chịu đựng chậm trên các cài đặt Windows 7 của tôi [MiKTeX dưới Python (x, y) hoặc Anaconda], vì vậy tôi đã thực hiện thêm mã này, và mọi thứ hoạt động tốt ở đó một lần nữa:

import platform  # Don't save as SVG if running under Windows. 
# 
# Plot code goes here. 
# 
fig.savefig('figure_name.png', dpi = 200) 
if platform.system() != 'Windows': 
    # In my installations of Windows 7, it takes an inordinate amount of time to save 
    # graphs as .svg files, so on that platform I've disabled the call that does so. 
    # The first run of a script is still a little slow while everything is loaded in, 
    # but execution times of subsequent runs are improved immensely. 
    fig.savefig('figure_name.svg') 
Các vấn đề liên quan