2012-01-21 21 views
65

मैं वर्तमान में विभिन्न पायथन प्लॉटिंग पुस्तकालयों का मूल्यांकन कर रहा हूं। अभी मैं matplotlib कोशिश कर रहा हूँ और मैं प्रदर्शन से काफी निराश हूँ। निम्नलिखित उदाहरण SciPy examples से संशोधित किया गया है और मुझे प्रति सेकंड केवल 8 फ्रेम देता है!Matplotlib के साथ साजिश क्यों धीमी है?

इसे तेज करने के किसी भी तरीके या क्या मुझे एक अलग प्लॉटिंग लाइब्रेरी चुननी चाहिए?

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

निम्नलिखित प्रासंगिक हो सकते हैं: http://stackoverflow.com/questions/5003094/how-can-i-speed-up-an-animation – NPE

+2

@aix - ग्लेम्पी ने केवल उस उदाहरण में मदद की क्योंकि वह तेजी से प्रदर्शित छवि से निपट रहा था डेटा। यह इस मामले में मदद नहीं करेगा। –

+1

बैकएंड को बदलने का प्रयास करें। मेरा उत्तर देखें: http://stackoverflow.com/a/30655528/2066079। या बैकएंड के बारे में यह FAQ: http://matplotlib.org/faq/usage_faq.html#what-is-a-backend – dberm22

उत्तर

85

सबसे पहले, (हालांकि यह प्रदर्शन बिल्कुल भी नहीं बदलेगा) अपने कोड, इस के समान को साफ करने पर विचार करें: ऊपर के उदाहरण के साथ

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) 

, मैं 10fps के आसपास मिलता है।

आपके सटीक उपयोग के मामले के आधार पर बस एक त्वरित नोट, matplotlib एक अच्छा विकल्प नहीं हो सकता है। यह प्रकाशन-गुणवत्ता वाले आंकड़ों की ओर उन्मुख है, वास्तविक समय के प्रदर्शन नहीं।

हालांकि, इस उदाहरण को गति देने के लिए आप बहुत सी चीजें कर सकते हैं।

दो मुख्य कारण हैं कि यह जितना धीमा है।

1) fig.canvas.draw() कॉलिंग सब कुछ पर कॉल करना। यह तुम्हारी बाधा है। आपके मामले में, आपको अक्ष की सीमाओं, टिक टिक, इत्यादि जैसी चीजों को फिर से खींचने की आवश्यकता नहीं है

2) आपके मामले में, बहुत सारे टिक लेबल वाले बहुत सारे सबप्लॉट हैं। इन्हें आकर्षित करने में काफी समय लगता है।

इन दोनों को ब्लिटिंग का उपयोग करके ठीक किया जा सकता है।

कुशलतापूर्वक मिश्रण करने के लिए, आपको बैकएंड-विशिष्ट कोड का उपयोग करना होगा। व्यावहारिक रूप से, यदि आप चिकनी एनिमेशन के बारे में वास्तव में चिंतित हैं, तो आप आमतौर पर कुछ प्रकार के गुई टूलकिट में matplotlib प्लॉट एम्बेड कर रहे हैं, इसलिए यह कोई समस्या नहीं है।

हालांकि, आप जो भी कर रहे हैं उसके बारे में कुछ और जानने के बिना, मैं आपकी मदद नहीं कर सकता।

फिर भी, ऐसा करने का एक गुई-तटस्थ तरीका है जो अभी भी काफी तेज़ है।

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) 

यह मुझे ~ 200fps देता है।

इसे थोड़ा और सुविधाजनक बनाने के लिए, matplotlib के हाल के संस्करणों में animations मॉड्यूल है।

एक उदाहरण के रूप:

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

आपका कोड वास्तव में बहुत तेज़ है, हालांकि मैं प्रति अक्ष 2000 लाइनों के साथ समाप्त होता हूं! किसी भी तरह "line.set_ydata" इसे अद्यतन करने की बजाय एक नई लाइन बनाता है - या पृष्ठभूमि को साफ़ नहीं किया जा रहा है? इसके अलावा, आपका संस्करण इतना तेज़ क्यों है? सिर्फ इसलिए कि आपने "draw()" गिरा दिया और इसे "ax.draw_artist" से बदल दिया? – memyself

+0

किस उदाहरण में? (मैंने उनका परीक्षण किया, लेकिन यह संभव है कि गलत संस्करण को गलत संस्करण में चिपकाया जाए।) इसके अलावा, matplotlib का कौन सा संस्करण आप उपयोग कर रहे हैं? –

+0

मेरा दूसरा उदाहरण है। मैं matplotlib संस्करण 1.0.1 का उपयोग करें। – memyself

12

matplotlib महान प्रकाशन गुणवत्ता ग्राफिक्स है, लेकिन बहुत अच्छी तरह से गति के लिए अनुकूल नहीं है। उस गति को ध्यान में रखकर बनाया गया है अजगर अंकन संकुल की एक किस्म है:

4

पहला समाधान Joe Kington (.copy_from_bbox & .draw_artist & canvas.blit) द्वारा प्रस्तावित के लिए सिफारिश कर रहा है, मैं पृष्ठभूमि पर कब्जा करने के लिए किया था fig.canvas.draw() लाइन के बाद, अन्यथा पृष्ठभूमि का कोई प्रभाव नहीं पड़ा और जैसा आपने बताया है वही परिणाम मिला। यदि आप इसे अंजीर के बाद डालते हैं। शो() यह अभी भी माइकल ब्राउन द्वारा प्रस्तावित कार्य के रूप में काम नहीं करता है।

तो बस पृष्ठभूमि लाइन डाल के बाद 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

आपको अलग-अलग – endolith

9

शुरू करने के लिए, Joe Kington's answer एक जीयूआई तटस्थ दृष्टिकोण का उपयोग कर बहुत अच्छा सलाह प्रदान करता है, और आप निश्चित रूप से लेना चाहिए उसके सलाह (विशेष रूप से ब्लिटिंग के बारे में) और इसे अभ्यास में डाल दें। इस दृष्टिकोण पर अधिक जानकारी, Matplotlib Cookbook

पढ़ें, हालांकि, गैर-जीयूआई-तटस्थ (जीयूआई-पक्षपातपूर्ण) दृष्टिकोण साजिश को तेज करने के लिए महत्वपूर्ण है। दूसरे शब्दों में, backend साजिश की गति के लिए बेहद महत्वपूर्ण है।

इन दो पंक्तियों रखो इससे पहले कि आप कुछ और आयात matplotlib से:

import matplotlib 
matplotlib.use('GTKAgg') 
बेशक

, वहाँ विभिन्न विकल्पों GTKAgg के बजाय का उपयोग करने के हैं, लेकिन रसोई की किताब पहले उल्लेख के अनुसार, इस सबसे तेजी से किया गया था। अधिक विकल्पों के लिए बैकएंड के बारे में लिंक देखें।

+0

के रूप में पोस्ट करने के बजाय बस अपना उत्तर संपादित करना चाहिए, हालांकि यह केवल विंडोज़ पर काम करता है, क्या आप इसे मैक पर काम करने के तरीके के बारे में जानते हैं। विंडोज़ विशिष्ट कारण यह है कि pygtk विंडोज विशिष्ट – user308827

+1

pygtk विंडोज विशिष्ट नहीं है। वास्तव में, यह विंडोज के तहत काम कर रहा एक बड़ा दर्द है (यदि यह भी संभव है, तो मैंने छोड़ दिया है।) –

1

यह आप में से कई पर लागू नहीं हो सकता है, लेकिन मैं आमतौर पर लिनक्स के तहत अपने कंप्यूटर का संचालन कर रहा हूं, इसलिए डिफ़ॉल्ट रूप से मैं अपने matplotlib प्लॉट को पीएनजी और एसवीजी के रूप में सहेजता हूं। यह लिनक्स के तहत ठीक काम करता है लेकिन मेरे विंडोज 7 इंस्टॉलेशन [माइक्रटेक्स के तहत पाइथन (एक्स, वाई) या एनाकोंडा के तहत असीमित रूप से धीमा है, इसलिए मैंने इस कोड को जोड़ने के लिए लिया है, और चीजें फिर से ठीक काम करती हैं:

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') 
संबंधित मुद्दे