为什么用Matplotlib绘制这么慢?

发布于 2021-02-02 23:12:17

我目前正在评估其他python绘图库。现在,我正在尝试使用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)
关注者
0
被浏览
115
1 个回答
  • 面试哥
    面试哥 2021-02-02
    为面试而生,有面试问题,就找面试哥。

    首先,(尽管这根本不会改变性能)考虑清理你的代码,类似于:

    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)在你的情况下,有很多带有很多刻度标签的子图。这些需要很长时间才能绘制出来。

    这两种都可以使用blitting进行修复。

    为了高效地进行blit,你必须使用特定于后端的代码。在实践中,如果你真的担心平滑的动画,那么无论如何,通常都将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()
    


知识点
面圈网VIP题库

面圈网VIP题库全新上线,海量真题题库资源。 90大类考试,超10万份考试真题开放下载啦

去下载看看