Matplotlib के साथ साजिश इतनी धीमी क्यों है?


100

मैं वर्तमान में पुस्तकालयों की साजिश रचने वाले विभिन्न अजगर का मूल्यांकन कर रहा हूं। अभी मैं matplotlib की कोशिश कर रहा हूं और मैं प्रदर्शन से काफी निराश हूं। निम्न उदाहरण SciPy उदाहरणों से संशोधित किया गया है और मुझे केवल ~ 8 फ्रेम प्रति सेकंड देता है!

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

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)

निम्नलिखित प्रासंगिक हो सकता है: stackoverflow.com/questions/5003094/…
NPE

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

1
बैकएंड बदलने की कोशिश करें। : मेरा उत्तर देखें stackoverflow.com/a/30655528/2066079 । या बैकएंड के बारे में यह अक्सर पूछे जाने वाले प्रश्न: matplotlib.org/faq/usage_faq.html#what-is-a-backend
dberm22

जवाबों:


115

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

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()redraws सब कुछ । यह आपकी अड़चन है। आपके मामले में, आपको कुल्हाड़ियों की सीमाओं, टिक लेबल आदि जैसी चीजों को फिर से आकर्षित करने की आवश्यकता नहीं है।

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

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

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

हालाँकि, आप क्या कर रहे हैं, इसके बारे में कुछ और जाने बिना, मैं वहाँ आपकी मदद नहीं कर सकता।

बहरहाल, इसे करने का एक ऐसा तटस्थ-तटस्थ तरीका है जो अभी भी यथोचित रूप से तेज़ है।

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 देता है।

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

उदहारण के लिए:

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

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

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

4
यहाँ परिणामी छवि का लिंक है I.imgur.com/aBRFz.png क्या यह मेरे ग्राफिक्स कार्ड के कारण की गई कलाकृति हो सकती है?
मेमोरियल

7
मैं वही चीज़ देख रहा था जो i.imgur.com/aBRFz.png में देख रहा था, जब तक कि मैं अंजीर के नीचे की पृष्ठभूमि पर कब्जा नहीं कर लेता। ()।
माइकल ब्राउन

4
अच्छा लगा, लेकिन समय-समय पर animationकथानक को अद्यतन करना प्रतीत होता है interval, क्या होगा यदि मैं नया डेटा तैयार होने पर इसे अद्यतन करना चाहता हूं?
अलकोट

28

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


1
मैं अच्छी तरह से वास्तविक समय स्ट्रीम डेटा के लिए pyqtgraph.org/documentation का आनंद लेता हूं । महान नौकरी
लुक

11

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

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

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

import matplotlib
matplotlib.use('GTKAgg') 

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


यह केवल विंडोज़ पर काम करता है, हालांकि, क्या आप मैक पर काम करने के तरीके के बारे में जानते हैं। विंडोज़ विशिष्ट होने का कारण यह है कि
pygtk

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

7

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

तो बस कैनवास लाइन के बाद पृष्ठभूमि लाइन रखो ():

[...]
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]

4
आपको बस एक अलग के रूप में पोस्टिंग के बजाय उसके उत्तर को संपादित करना चाहिए
एंडोलिथ

1

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

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')
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.