Home > Software design >  How to generate an animation composed of several plots in python?
How to generate an animation composed of several plots in python?

Time:09-23

I'm having trouble plotting an animation with python. What I want to do is basically an animation that contains the superposition of many complete plots. In such a way that each frame will be a plot given by

plt.plot(r, Sevol[n])

The code and error displayed on the screen are below. Thanks for any help.

UserWarning: Animation was deleted without rendering anything. This is most likely not intended. To prevent deletion, assign the Animation to a variable, e.g. anim, that exists until you have outputted the Animation using plt.show() or anim.save().

import numpy as np
import math
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation

nr = 300
ri = 0
rf = 300
dr = (rf - ri) / (nr - 1)
nt = 1000
dt = 0.1

r = np.linspace(ri, rf, num=nr)

def rk3_step(t, h, y, f, *args):
    k1 = h * f(t      , y              , *args)
    k2 = h * f(t   h/2, y   1/2 * k1   , *args)
    k3 = h * f(t   h  , y - k1   2 * k2, *args)
    return y   1/6*(k1   4*k2   k3)


def rhs_perturb(t, u):
    S = u.T[0]
    S_dot = u.T[1]
    F = u.T[2]
    F_dot = u.T[3]
    rhs = np.empty((nr, 4))

    rhs[0] = np.array([S_dot[0],
                       (S[2] - 2 * S[1]   S[0]) / (dr ** 2),  #   F[0],
                       F_dot[0],
                       - S[0]   (F[2] - 2 * F[1]   F[0]) / (dr ** 2)])
    rhs[-1] = np.array([S_dot[-1],
                        (S[-1] - 2 * S[-2]   S[-3]) / (dr ** 2),  #   F[-1],
                        F_dot[-1],
                        - S[-1]   (F[-1] - 2 * F[-2]   F[-3]) / (dr ** 2)])
    for i in range(1, nr - 1):
        rhs[i] = np.array([S_dot[i],
                           (S[i   1] - 2 * S[i]   S[i - 1]) / (dr ** 2),  #   F[i],
                           F_dot[i],
                           - S[i]   (F[i   1] - 2 * F[i]   F[i - 1]) / (dr ** 2)])
    return rhs

sigma = 3
r0 = 100

F = np.empty(nr)
F_dot = np.empty(nr)
S = np.empty(nr)
S_dot = np.empty(nr)

for i in range(nr):
    F[i] = 0
    F_dot[i] = 0
    S_dot[i] = 0
    S[i] = math.exp(-(r[i] - r0)**2 / sigma**2)

uin = np.block([[S], [S_dot], [F], [F_dot]]).T
u = np.copy(uin)
uaux = np.copy(uin)

nsave = 10
Sevol = np.empty((math.floor(nt/nsave),nr))
Sevol[0] = S
Fevol = np.empty((math.floor(nt/nsave),nr))
Fevol[0] = F

for n in range(nt):
    uaux = rk3_step(n * dt, dt, u, rhs_perturb)    
    if np.any(np.isnan(uaux)):
        break    
    u = uaux
    if (n   1) % nsave == 0:
        Sevol[math.floor(n / nsave)] = u.T[0]
        Fevol[math.floor(n / nsave)] = u.T[2]

fig = plt.figure()

plt.xlabel('r')
plt.xlabel('S')
plt.grid()
plt.xlim(ri, rf)

def animate(i):
    numPlots = i //10    # how many plots (-1) will be shown based on the frame.
    for n in range(numPlots):
        plt.plot(r[n], Sevol[n], color='gold', markersize=3)

ani = FuncAnimation(fig, animate, frames=100, interval=10, blit = False, repeat = False)

plt.close()

plt.show()

CodePudding user response:

I would suggest initializing your animations with a list of empty placeholders plots. In your case, it looks like you need 100 plots. And then update the data for plot i at each frame with the actual values.

Below is what the animation code looks like:

import numpy as np
import math
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation, PillowWriter

N_plots=100
fig,ax = plt.subplots()
color = plt.cm.viridis(np.linspace(0, 1, N_plots))
lns=[ax.plot([],[],color=color[i]) for i in range(N_plots)]
lns=[lns[i][0] for i in range(N_plots)]
plt.xlabel('r')
plt.ylabel('S')
plt.grid()
plt.xlim(ri, rf)
plt.ylim(-0.25, 1)


def animate(i):
  lns[i].set_data(r,Sevol[i])
  return lns

ani = FuncAnimation(fig, animate, frames=N_plots, interval=100)

And the output gives:

enter image description here

EDIT:

Note that if instead of superimposing the curves you just want to replace them by the next, you can simply use set_data to update your one plot. See code below:

import numpy as np
import math
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation, PillowWriter

N_plots=100
fig,ax = plt.subplots()
color = plt.cm.viridis(np.linspace(0, 1, N_plots))
ln,=ax.plot([],[]) 
plt.xlabel('r')
plt.ylabel('S')
plt.grid()
plt.xlim(ri, rf)
plt.ylim(-0.25, 1)


def animate(i):
  ln.set_data(r,Sevol[i])
  ln.set_color(color[i])
  return ln

ani = FuncAnimation(fig, animate, frames=N_plots, interval=100)

And the output gives:

enter image description here

  • Related