Search code examples
pythonimagematplotlibanimationmatplotlib-animation

Animate labels using FuncAnimation in Matplotlib


I am not able to make (animated) labels using FuncAnimation from matplotlib. Please find below a minimal code that I made. ax.annotate has no effect at all - the animation itself works though. What can I change to get animated labels/titles, which are different for each frame?

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

fig, ax = plt.subplots()
fig.clear()
steps = 10
data = np.random.rand(20,20,10)
imagelist = [data[:,:,i] for i in range(steps) ]
im = plt.imshow(imagelist[0], cmap='Greys',  origin='lower', animated=True)
plt.colorbar(shrink=1, aspect=30, label='Counts')

# does not work
ax.annotate("Frame: %d " % steps,(0.09,0.92),xycoords ='figure fraction')  

def updatefig(j):
    im.set_array(imagelist[j])
    return [im]

ani = animation.FuncAnimation(fig, updatefig, frames=range(steps), interval=200, blit=True)
plt.show()

Solution

  • Two problems overall:

    • The annotation text never gets updated in updatefig()
    • The canvas gets cleared+blitted, which wipes out annotations

    Five steps to resolve:

    1. Remove fig.clear() to preserve annotations
    2. Save the initial annotation's handle
    3. Update the annotation's text in updatefig()
    4. Include the annotation in the return of updatefig()
    5. Set blit=False to preserve annotations
    import numpy as np
    import matplotlib.pyplot as plt
    import matplotlib.animation as animation
    
    fig, ax = plt.subplots()
    #1 do NOT call fig.clear()
    
    steps = 10
    data = np.random.rand(20, 20, steps)
    im = plt.imshow(data[:, :, 0], cmap='Greys', origin='lower', animated=True)
    plt.colorbar(shrink=1, aspect=30, label='Counts')
    
    #2 annotate frame 0 and save handle
    annot = ax.annotate('Frame: 0', (0.09, 0.92), xycoords='figure fraction')
    
    def updatefig(j):
        im.set_array(data[:, :, j])
    
        #3 update annotation text
        annot.set_text(f'Frame: {j}')
    
        #4 include annotation when returning
        return im, annot
    
    #5 set blit=False
    anim = animation.FuncAnimation(fig, updatefig, frames=steps, blit=False)