Matplotlib动画在添加补丁时会变慢 [英] Matplotlib animation slows down when adding patches

查看:208
本文介绍了Matplotlib动画在添加补丁时会变慢的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想可视化2D算法的路径。所以我写了一段简短的Python代码,产生了这样的动画。问题是,对于我添加的每个像素( plt.Rectangle ),代码变得越来越慢。前20个像素在大约1秒钟内显示,后20个像素已经花费3秒钟。对于更大的网格和更多的像素,显然情况变得更糟。

I wanted to visualize the path of a 2D-algorithm. So I wrote a short Python code, that produces such a animation. The problem is, that for each pixel (a plt.Rectangle) I add, the code gets slower and slower. The first 20 pixels get displayed in about 1 second, the last 20 pixels take already 3 seconds. And obviously it gets even worse for bigger grids and more pixels.

from matplotlib import pyplot as plt
from matplotlib import animation

fig = plt.figure()
fig.set_dpi(100)
fig.set_size_inches(7, 7)
ax = plt.axes(xlim=(0, 20), ylim=(0, 20))

pixels = list()

def init():
    return list()

def animate(i):
    index = len(pixels)
    index_x, index_y = index // 20, index % 20

    pixel = plt.Rectangle((index_x, index_y), 1, 1, fc='r')
    ax.add_patch(pixel)
    pixels.append(pixel)
    return pixels

anim = animation.FuncAnimation(fig, animate, 
                               init_func=init, 
                               frames=100, 
                               interval=5,
                               blit=True)

plt.show()

我很清楚,为什么需要更长的时间。由于每帧补丁的数量越来越大,因此matplotlibs渲染变得越来越慢。但是,这不慢!如何提高速度?有没有办法可以保留旧图并仅覆盖当前像素?

It's quite clear to me, why it takes longer. Since the number of patches gets bigger and bigger each frame, matplotlibs rendering gets slower and slower. But not this slow! How can I get more speed? Is there a way that I can keep the old plot and only overwrite the current pixel?

推荐答案

我尝试对动画功能进行计时,并且由于某种原因,函数本身并没有明显的减速。此外, blit 应该确保仅绘制最新的矩形。防止您建议重绘的一种可能方法是使用以下方法栅格化绘图:

I tried timing the animate function and for some reason there is no apparent slowdown in the function itself. Besides, blit should ensure only the latest rectangle is drawn. A possible way to prevent the redraw you suggest is to rasterize the plot with,

    m=ax.add_patch(pixel)
    m.set_rasterized(True)

尽管这似乎并没有提高我的计时速度。我认为在更新绘图时,增加一定会导致在matplotlib中出现。使用交互式绘图很明显,例如

Although this doesn't seem to improve speed for my timing. I think the increase must result somewhere in matplotlib when updating the plot. This is clear using interactive plotting, e.g.

from matplotlib import pyplot as plt
import time

fig = plt.figure()
fig.set_dpi(100)
fig.set_size_inches(7, 7)
ax = plt.axes(xlim=(0, 20), ylim=(0, 20))
npx = 20; npy = 20
Npix = npx*npy
plt.ion()
plt.show()
for i in range(Npix):
    #ax.cla()
    t0 = time.time()
    index_x, index_y = i // 20, i % 20

    pixel = plt.Rectangle((index_x, index_y), 1, 1, fc='r')
    ax.add_patch(pixel)

    fig.set_rasterized(True)
    plt.pause(0.0001)
    t1 = time.time()
    print("Time=",i,t1-t0)

给出了栅格化,非栅格化和清除的轴( ax.cla )的情况,

Which gives for the rasterised, non-rasterised and cleared axis (ax.cla) case,

我不确定为什么会这样,也许对matplotlib有更深入了解的人可以提供帮助。一种加快绘图速度的方法是设置所有矩形并将它们放置在 patchcollection 中。然后动画只是改变了面色,因此只显示需要显示的矩形,

I'm not sure why this happens, maybe someone with better insight into matplotlib would be able to help. One way to speed up the plot is to setup and put all rectangles in a patchcollection. Then the animation just changes the facecolor so only the rectangles which need be shown are displayed,

from matplotlib import pyplot as plt
from matplotlib import animation
import numpy as np

from matplotlib.collections import PatchCollection

fig = plt.figure()
fig.set_dpi(100)
fig.set_size_inches(7, 7)
ax = plt.axes(xlim=(0, 20), ylim=(0, 20))
npx = 20; npy = 20
Npix = npx*npy
displayed = np.zeros((npx, npy, 4))
pixels = []

def init():
    for index in range(Npix):
        index_x, index_y = index // npx, index % npy

        pixel = plt.Rectangle((index_x, index_y), 1, 1, fc='r', ec='none')
        pixels.append(pixel)

    return pixels

pixels = init()
collection = PatchCollection(pixels, match_original=True, animated=True)
ax.add_collection(collection)

def animate(index):
    index_x, index_y = index // npx, index % npy
    displayed[index_x, index_y] = [1, 0, 0, 1]
    collection.set_facecolors(displayed.reshape(-1, 4))
    return (collection,)

anim = animation.FuncAnimation(fig, animate, 
                               frames=400,
                               interval=1, 
                               blit=True, 
                               repeat=False)

plt.show()        

这要快得多,尽管我无法弄清楚如何打开或关闭边缘,所以禁用所有矩形。

This is much faster, although I couldn't work out how to turn edges on or off so just disable for all rectangles.

这篇关于Matplotlib动画在添加补丁时会变慢的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆