Search code examples
pythonanimationmatplotlibshading

Python animation shadings matplotlib


So I am trying to create an animation of a few Gaussian Graphs that move over time. I have the basic animation working as I intended it too. But then I wanted to shade the area under the Gaussian Curves. I used ax.fill function to shade it. But instead it just shades the drawing vector that creates the curves, and it just becomes a mess. Any suggestions or help would be much appreciated

import numpy as np
import matplotlib.pyplot as plt
plt.switch_backend('agg')
import matplotlib.animation as animation
import pylab as p

Gamma=0.0005
q=1.6e-19
m=0.067*9e-31
B=10
Ec=(1.0567e-34)*B/m
#e=2.78

#E0=0+(1.0567e-34)*x*i/m

fig, ax = plt.subplots()

n = 3 #number of lines
x = np.arange(0, 3.6e-3, 1.7e-5)        # x-array, third number is interval here, x is energy
lines = [ax.plot(x, np.e**(-(x-((1.0567e-34)*1*1/m))**2/Gamma**2))[0]for _ in range(n)]


def animate(i):
    for d, line in enumerate(lines):
        p=(d+1)/2.
        line.set_ydata(np.e**((-(x-((1.0567e-34)*p*i/m))**2)/Gamma**2))
        ax.fill(x,(np.e**(-(x-((1.0567e-34)*p*i/m))**2/Gamma**2)), "b")# update the data
    return lines


#Init only required for blitting to give a clean slate.
def init():
    for line in lines:
        line.set_ydata(np.ma.array(x, mask=True))
    return lines

ani = animation.FuncAnimation(fig, animate, np.arange(0, 2.5, .01), init_func=init,
    interval=10, blit=True)
Writer = animation.writers['ffmpeg']
writer = Writer(fps=20, metadata=dict(artist='Me'), bitrate=1800)

ani.save('QHanimati.mp4', writer=writer)



plt.show()

So the current code runs an animation that gives something like this. Curve

And I want it to leave the area above the curve white.

Thanks.


Solution

  • You need to be aware that the animation that is saved is the animation that would be shown if blit=False. So what happens is that the fills are all added up to the canvas.

    A solution is to remove the previous one before adding the next (as something like set_data does not directly exist for fills).

    Again, we would create a list of fills, and actually use fill_between, instead of fill which we can use to remove the fills and add new ones to it.

    import numpy as np
    import matplotlib.pyplot as plt
    import matplotlib.animation as animation
    
    
    Gamma=0.0005
    q=1.6e-19
    m=0.067*9e-31
    B=10
    Ec=(1.0567e-34)*B/m
    
    fig, ax = plt.subplots()
    
    n = 3 #number of lines
    x = np.arange(0, 3.6e-3, 1.7e-5)        # x-array, third number is interval here, x is energy
    lines = [ax.plot(x, np.e**(-(x-((1.0567e-34)*1*1/m))**2/Gamma**2), zorder=i+3)[0] for i in range(n)]
    fills = [ax.fill_between(x,0,(np.e**(-(x-((1.0567e-34)*1*1/m))**2/Gamma**2)), facecolor=lines[i].get_color(), zorder=i+3) for i in range(n)]
    
    
    def animate(i):
        for d, line in enumerate(lines):
            p=(d+1)/2.
            line.set_ydata(np.e**((-(x-((1.0567e-34)*p*i/m))**2)/Gamma**2))
            fills[d].remove()
            fills[d] = ax.fill_between(x,0,(np.e**(-(x-((1.0567e-34)*p*i/m))**2/Gamma**2)), facecolor=lines[d].get_color(), zorder=d+3)# update the data
    
        return lines + fills
    
    
    #Init only required for blitting to give a clean slate.
    def init():
        for line in lines:
            line.set_ydata(np.ma.array(x, mask=True))
        return lines
    
    ani = animation.FuncAnimation(fig, animate, np.arange(0, 2.5, .01), init_func=init,
        interval=10, blit=True)
    #Writer = animation.writers['ffmpeg']
    #writer = Writer(fps=20, metadata=dict(artist='Me'), bitrate=1800)
    #
    #ani.save('QHanimati.mp4', writer=writer)
    
    plt.show()
    

    enter image description here