Search code examples
pythonmatplotlibjupyter-notebookcartopy

Matplotlib / Cartopy - Animation Blank using FuncAnimation in Jupyter Notebooks


I had this same animation working using the IPython Display module, but I want it to be interactive so I'm trying to use the matplotlib animation module. If I run the below with %matplotlib notebook it just returns a blank screen. If I run it with %matplotlib inline it returns only the first frame. If I run in inline mode and save it as an HTML5 video using the HTML module in IPython.dispay, it shows a video of a blank white screen, and below that it shows the last frame (not the first frame).

Below is code:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cm
from matplotlib import colors
from matplotlib import animation
import random

import cartopy.crs as ccrs
from cartopy.io.shapereader import Reader
from cartopy.feature import ShapelyFeature

fname = r'D:\Downloads\gadm36_USA_shp\gadm36_USA_2.shp'

fig = plt.figure()
ax = plt.axes((-82.65, 27.65, 0.595, 0.5), projection=ccrs.PlateCarree())
shape_feature = ShapelyFeature(Reader(fname).geometries(), ccrs.PlateCarree(), edgecolor='black')
ax.add_feature(shape_feature, alpha=0.5)

ax.set_extent([-82.65,-82.055,27.65,28.15])

cmap = colors.ListedColormap(['0000', 'green', 'yellow', 'orange', 'red'])
bounds = [0, .25, .5, .75, .9, 1]
norm = colors.BoundaryNorm(bounds, cmap.N)
pdf = plt.imshow(np.zeros((20,20)), cmap=cmap, extent=(-82.65,-82.055,27.65,28.15))

def search():
    ...
    yield [op, norm]
    ...

def plot_search(args):
    op = args[0]
    updated_norm = args[1]

    new_z = op.reshape((20,20))

    pdf.set_norm(updated_norm)
    pdf.set_data(new_z)
    return [pdf]
ani = animation.FuncAnimation(fig, plot_search, frames=search, blit=True)
plt.plot()

search() is a generator function. Even if I wrap it with list(search()), it still doesn't work.

I'm new to matplotlib / cartopy, so any help is greatly appreciated!


Solution

  • Your definition when calling axes is a little odd. I think when you were using the notebook, it saves by using a "tight" bounding box, which means it automatically resizes the image to fit what's on the plot--in your case it was making the image bigger. When using it outside the notebook, the default image doesn't fit the axes you defined. The following works for me:

    import numpy as np
    import matplotlib.pyplot as plt
    from matplotlib import cm
    from matplotlib import colors
    from matplotlib import animation
    import random
    
    import cartopy.crs as ccrs
    from cartopy.io.shapereader import Reader
    from cartopy.feature import ShapelyFeature
    
    #fname = r'D:\Downloads\gadm36_USA_shp\gadm36_USA_2.shp'
    
    fig = plt.figure()
    ax = plt.axes(projection=ccrs.PlateCarree())
    #shape_feature = ShapelyFeature(Reader(fname).geometries(), ccrs.PlateCarree(), edgecolor='black')
    #ax.add_feature(shape_feature, alpha=0.5)
    
    ax.set_extent([-82.65,-82.055,27.65,28.15])
    
    cmap = colors.ListedColormap(['0000', 'green', 'yellow', 'orange', 'red'])
    bounds = [0, .25, .5, .75, .9, 1]
    norm = colors.BoundaryNorm(bounds, cmap.N)
    pdf = plt.imshow(np.zeros((20,20)), cmap=cmap, extent=(-82.65,-82.055,27.65,28.15))
    
    def search():
        yield np.random.randn(400), plt.Normalize(-1, 1)
    
    def plot_search(args):
        op, updated_norm = args
    
        new_z = op.reshape((20,20))
    
        pdf.set_norm(updated_norm)
        pdf.set_data(new_z)
        return [pdf]
    ani = animation.FuncAnimation(fig, plot_search, frames=search, blit=True)
    plt.show()
    

    You can also see this example on what the parameters look like if you're manually creating an axes.