[python] Matplotlib로 플로팅하는 것이 왜 그렇게 느린가요?

현재 다른 파이썬 플로팅 라이브러리를 평가하고 있습니다. 지금은 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)



답변

먼저 (성능에 전혀 영향을주지 않지만) 다음과 같이 코드를 정리하는 것이 좋습니다.

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


답변

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


답변

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

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

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

import matplotlib
matplotlib.use('GTKAgg') 

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


답변

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]


답변

이것은 많은 사람들에게 적용되지 않을 수 있지만 일반적으로 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')


답변