Matplotlib funcanimation blit slow
Question: I'm having issues with a slow animation in Matplotlib. I'm animating results
from a simulation, which is easiest visualized with an array of rectangles
that change color with time.

Following recommendations
[here](http://stackoverflow.com/questions/8955869/why-is-plotting-with-
matplotlib-so-slow/8956211#8956211), I'm using blitting to only draw the
(small fraction) of rectangles that change in each frame. I also tried to
implement this using FuncAnimation, but when using that with Blit=True, the
script runs much slower.

I'm wondering if this is because I'm returning _all_ of the rectangles to
FuncAnimation, so it redraws all of them even if they haven't changed. Is
there a way to pass different artists at each frame to FuncAnimation? I tried
just passing a tuple of the ones that had changed (the commented out block in
the "animate" function), but that led to seemingly random animation frames...

Use:

    
    
    $ python2 [script].py blit
    $ python2 [script].py anim
    

Thanks!

    
    
    import sys
    import numpy as np
    import matplotlib
    matplotlib.use("TkAgg")
    import matplotlib.pyplot as plt
    import matplotlib.animation as manim
    
    def animate_data(plot_type):
        """
        Use:
        python2 plot_anim.py [option]
        option = anim OR blit
        """
    
        # dimension parameters
        Nx = 30
        Ny = 20
        numtimes = 100
        size = 0.5
    
        if plot_type == "blit":
            # "interactive mode on"
            plt.ion()
        # Prepare to do initial plot
        fig = plt.figure()
        ax = fig.add_subplot(1,1,1)
        ax.set_aspect('equal', 'box')
        ax.xaxis.set_major_locator(plt.NullLocator())
        ax.yaxis.set_major_locator(plt.NullLocator())
        # An array in which to store the rectangle artists
        rects = np.empty((Nx, Ny), dtype=object)
        # Generate initial figure of all green rectangles
        for (i,j),k in np.ndenumerate(rects):
            color = 'green'
            rects[i, j] = plt.Rectangle([i - size / 2, j - size / 2],
                    size, size, facecolor=color, edgecolor=color)
            ax.add_patch(rects[i, j])
        ax.autoscale_view()
    
        # "Old" method using fig.canvas.blit()
        if plot_type == "blit":
            plt.show()
            fig.canvas.draw()
            # Step through time updating the rectangles
            for tind in range(1, numtimes):
                updated_array = update_colors(rects)
                for (i, j), val in np.ndenumerate(updated_array):
                    if val:
                        ax.draw_artist(rects[i, j])
                fig.canvas.blit(ax.bbox)
    
        # New method using FuncAnimate
        elif plot_type == "anim":
            def animate(tind):
                updated_array = update_colors(rects)
    #            # Just pass the updated artists to FuncAnimation
    #            toupdate = []
    #            for (i, j), val in np.ndenumerate(updated_array):
    #                if val:
    #                    toupdate.append(rects[i, j])
    #            return tuple(toupdate)
                return tuple(rects.reshape(-1))
            ani = manim.FuncAnimation(fig, animate, frames=numtimes,
                    interval=10, blit=True, repeat=False)
            plt.show()
    
        return
    
    # A function to randomly update a few rectangles
    def update_colors(rects):
        updated_array = np.zeros(rects.shape)
        for (i, j), c in np.ndenumerate(rects):
            rand_val = np.random.rand()
            if rand_val < 0.003:
                rects[i, j].set_facecolor('red')
                rects[i, j].set_edgecolor('red')
                updated_array[i, j] = 1
        return updated_array
    
    if __name__ == "__main__":
        if len(sys.argv) > 1:
            plot_type = sys.argv[1]
        else:
            plot_type = "blit"
        animate_data(plot_type)
    


Answer: Update 600 rectangles every frame is very slow, `cbar_blit` mode in your code
is faster because you only update the rectangles which's color is changed. You
can use `PatchCollection` to speedup drawing, here is the code:

    
    
    import numpy as np
    import matplotlib
    matplotlib.use("TkAgg")
    import matplotlib.pyplot as plt
    import matplotlib.animation as manim
    from matplotlib.collections import PatchCollection
    
    Nx = 30
    Ny = 20
    numtimes = 100
    
    size = 0.5
    
    x, y = np.ogrid[-1:1:30j, -1:1:20j]
    
    data = np.zeros((numtimes, Nx, Ny))
    
    for i in range(numtimes):
        data[i] = (x-i*0.02+1)**2 + y**2
    
    colors = plt.cm.rainbow(data)
    
    fig, ax = plt.subplots()
    
    rects = []
    for (i,j),c in np.ndenumerate(data[0]):
        rect = plt.Rectangle([i - size / 2, j - size / 2],size, size)
        rects.append(rect)
    
    collection = PatchCollection(rects, animated=True)
    
    ax.add_collection(collection)
    ax.autoscale_view(True)
    
    
    def animate(tind):
        c = colors[tind].reshape(-1, 4)
        collection.set_facecolors(c)    
        return (collection,)
    
    ani = manim.FuncAnimation(fig, animate, frames=numtimes,
            interval=10, blit=True, repeat=False)
    
    plt.show()        
    

