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는 이미지 데이터를 빠르게 표시하는 것을 다루었 기 때문에이 예제에서만 도움이되었습니다. 이 경우에는 도움이되지 않습니다.
Joe Kington

1
백엔드를 변경해보십시오. 내 대답을 참조하십시오 : stackoverflow.com/a/30655528/2066079 . 또는 백엔드에 대한 FAQ : 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() 다시 그려 집니다. 병목 현상입니다. 귀하의 경우 축 경계, 눈금 레이블 등과 같은 것을 다시 그릴 필요가 없습니다.

2) 귀하의 경우에는 눈금 레이블이 많은 서브 플롯이 많이 있습니다. 그리는 데 시간이 오래 걸립니다.

둘 다 블리 팅을 사용하여 수정할 수 있습니다.

블리 팅을 효율적으로 수행하려면 백엔드 별 코드를 사용해야합니다. 실제로 부드러운 애니메이션에 대해 정말로 걱정한다면, 어쨌든 일종의 GUI 툴킷에 matplotlib 플롯을 포함 시키므로 이는 큰 문제가 아닙니다.

그러나 당신이하는 일에 대해 조금 더 알지 못하면 나는 당신을 도울 수 없습니다.

그럼에도 불구하고 여전히 상당히 빠른 GUI 중립적 인 방법이 있습니다.

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"는 업데이트하는 대신 새 줄을 만듭니다. 아니면 배경이 지워지지 않고 있습니까? 또한 버전이 훨씬 빠른 이유는 무엇입니까? "draw ()"를 삭제하고 "ax.draw_artist"로 대체했기 때문입니까?
memyself

어떤 예에서? (나는 그들을 테스트했지만 잘못된 버전을 답에 복사하여 붙여 넣을 수 있습니다.) 또한 어떤 버전의 matplotlib를 사용하고 있습니까?
Joe Kington

4
여기에 결과 이미지에 대한 링크가 있습니다. i.imgur.com/aBRFz.png 이것이 내 그래픽 카드로 인한 인공물 일 수 있습니까?
memyself

7
i.imgur.com/aBRFz.png에서 배경 캡처를 fig.show () 아래 로 옮길 때까지 나 자신이 본 것과 동일한 것을보고있었습니다 .
Michael Browne

4
좋지만 일정 기간 동안 animation플롯을 업데이트하는 것 같습니다. interval새 데이터가 준비되었을 때 업데이트하고 싶다면 어떻게해야합니까?
Alcott 2014 년

28

Matplotlib는 훌륭한 출판 품질의 그래픽을 만들지 만 속도에 최적화되어 있지는 않습니다. 속도를 염두에두고 설계된 다양한 파이썬 플로팅 패키지가 있습니다.


1
실시간 스트림 데이터에 대한 pyqtgraph.org/documentation 을 완전히 즐깁니다 . 훌륭한 일 루크
qrtLs

11

시작하려면 Joe Kington의 답변 은 GUI 중립적 접근 방식을 사용하여 매우 좋은 조언을 제공하며, 그의 조언 (특히 Blitting에 대한)을 확실히 받아 실행해야합니다. 이 접근 방식에 대한 자세한 내용은 Matplotlib Cookbook을 참조하십시오.

그러나 비 GUI 중립 (GUI 편향?) 접근 방식은 플로팅 속도를 높이는 데 중요합니다. 즉, 백엔드 는 속도를 플롯하는 데 매우 중요합니다.

matplotlib에서 다른 것을 가져 오기 전에 다음 두 줄을 넣으십시오.

import matplotlib
matplotlib.use('GTKAgg') 

물론 대신 사용할 수있는 다양한 옵션이 GTKAgg있지만 앞서 언급 한 요리 책에 따르면 이것이 가장 빠릅니다. 더 많은 옵션은 백엔드에 대한 링크를 참조하십시오.


이것은 Windows에서만 작동하지만 Mac에서 작동하는 방법을 알고 있습니까? 그 이유는 윈도우의 특정이 pygtk 윈도우의 특정입니다입니다
user308827가

2
pygtk는 Windows에만 국한되지 않습니다. 사실, (그것도 가능하다면, 내가 포기했습니다.) Windows에서 작업을 받고 엄청난 고통
조셉 레드 펀

7

Joe Kington이 제안한 첫 번째 솔루션 (.copy_from_bbox & .draw_artist & canvas.blit)의 경우 fig.canvas.draw () 라인 의 배경을 캡처해야했습니다 . 그렇지 않으면 배경이 효과가 없었고 다음과 같은 결과를 얻었습니다. 당신이 언급했습니다. fig.show () 뒤에 넣으면 Michael Browne이 제안한대로 작동하지 않습니다.

따라서 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]

4
당신은 별도의 하나로 대신에 게시 그의 대답을 편집해야합니다
endolith

1

이것은 많은 사람들에게 적용되지 않을 수 있지만 일반적으로 Linux에서 컴퓨터를 작동하므로 기본적으로 matplotlib 플롯을 PNG 및 SVG로 저장합니다. 이것은 Linux에서는 잘 작동하지만 Windows 7 설치 [Python (x, y) 또는 Anaconda의 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')
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.