Search code examples
matplotlibanimationtitlecartopycontourf

how to animate over time properly. static background map (cartopy) + dynamic contourf + dynamic title


I'm stuck trying to create an animation of a contourf representation of concentration over a map, the main code I've been using is:

tiler = Stamen('terrain-background')

fig, ax = plt.subplots(figsize=[10,10],subplot_kw=dict(projection=ccrs.AlbersEqualArea()))
    ax.set_extent([-6.5, -4.5, 35.5, 37])
    ax.add_image(tiler,11)
    ax.gridlines(draw_labels=True, dms=True, x_inline=False, y_inline=False)
    cf = ax.contourf(LON,LAT, Z[:,:,0]*np.nan,
        levels=[1e-3,1e-2,1e-1,10,100,1000],
        cmap=plt.get_cmap('gist_heat_r'),
        alpha = 0.65,
        antialiased=True,
        norm = LogNorm(),
        transform=ccrs.PlateCarree()
        )
    cbar = fig.colorbar(cf)
    cbar.set_label('mg/m^3')
    
    def update(i):
        ax.contourf(LON,LAT, Z[:,:,i],
            levels=[1e-3,1e-2,1e-1,10,100,1000],
            cmap=plt.get_cmap('gist_heat_r'),
            alpha = 0.65,
            antialiased=True,
            norm = LogNorm(),
            transform=ccrs.PlateCarree()
            )
        plt.title('{} average concentration. date: {}'.format(avg_label[i], date_label[i]))      
    
    ani = animation.FuncAnimation(fig, update, frames=Z.shape[2], interval=1500)
    plt.show()

Everything is ok with the exception that the contourf representations do not refresh the information in each step. In every step, the previous representations of the older frames are still presents. So, finally, result in the last frame is equal to the overlapping of the 4 represented frames.

How can I change this behaviour without losing the background map? I only want to show the Z[:,:,i] in each frame.

My resulting figure in the last frame is like this one:

Thank you in advance!


Solution

  • A sequence of patches is stored in collections. Every time update is called a new patch is added. Therefore, you will need to clear previous patches by incorporating the following line in the update function. Moreover, you want to have blit=False because the axes are being modified.

    ax.collections.clear()