Search code examples
pythonmatplotlibanimationsaveblit

matplotlib animation save is not obeying blit=True but it seems to work just fine in plt.show()


I'm quite new to Python and am trying to animate text using matplotlib. used several online examples to arrive at the following code:

import matplotlib.pyplot as plt
import matplotlib.animation as animation

fig, ax = plt.subplots()

plt.xlabel('Distance')
plt.ylabel('Height')
plt.title('Object Trajectory \n')

plt.legend(loc="upper right", markerscale=4, fontsize=10)
plt.grid()

text=ax.text(3,1,'Moving Text', ha="left", va="bottom",clip_on=True,rotation=90,fontsize=15)    
text2=ax.text(0,1,'Moving Text', ha="left", va="bottom",clip_on=True,fontsize=15)    

def init():
    ax.set_xlim(0,10)
    ax.set_ylim(0,10)
    return text,text2

def update(frame):        
    #Moving a text
    text=ax.text(3,1+(int(frame))/30,'Moving Text', ha="left", va="bottom",clip_on=True,rotation=90,fontsize=15)    
    text2=ax.text(0+(int(frame))/30,1,'Moving Text', ha="left", va="bottom",clip_on=True,fontsize=15)    

    return text,text2

anim = animation.FuncAnimation(fig, update, init_func=init, frames=120, interval=10, blit=True)

anim.save('try_animation.mp4',dpi=160,fps=30, writer="ffmpeg")

plt.show()

So when I run it in console, I can see the texts moving nicely. But when I save it to a MP4 file the text doesn't seem to blit. Please Help.

Thank You

This is a screenshot of saved video file


Solution

  • What you observe is the expected behaviour. Blitting is a technique used to refresh only part of a graphics output. In the matplotlib case, instead of drawing the complete figure, only part of it, namely the region inside the axes, is refreshed and only those artists returned by the animating function are drawn. This allows to have a faster animation speed on screen.

    However, when an animation is saved, each frame needs to be drawn in completeness.

    So in order to have a text moving, one should rather update a single text's position, instead of creating new texts over and over again. This can be done with

    text.set_position((x,y))
    

    The example would hence look like

    import matplotlib.pyplot as plt
    import matplotlib.animation as animation
    
    fig, ax = plt.subplots()
    
    plt.xlabel('Distance')
    plt.ylabel('Height')
    plt.title('Object Trajectory \n')
    plt.grid()
    
    text=ax.text(3,1,'Moving Text', ha="left", va="bottom",clip_on=True,rotation=90,fontsize=15)    
    text2=ax.text(0,1,'Moving Text', ha="left", va="bottom",clip_on=True,fontsize=15)    
    
    def init():
        ax.set_xlim(0,10)
        ax.set_ylim(0,10)
        return text,text2
    
    def update(frame):        
        #Moving a text
        text.set_position((3, 1+(int(frame))/30))
        text2.set_position((0+(int(frame))/30,1))
        return text,text2
    
    anim = animation.FuncAnimation(fig, update, init_func=init, frames=120, interval=10, blit=True)
    
    anim.save('try_animation.mp4',dpi=160,fps=30, writer="ffmpeg")
    
    plt.show()