How to generate an animation composed of several plots in python? - python

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()

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:
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:

Related

Simulate a rotating equal triangle by Python

can anyone help me, i stuck at the last step
[]
this is my code. then for the last step to rotate it, i didnt know what should i do to rotate the triangle
This is the perfect case for an animation:
import matplotlib.pyplot as plt
import numpy as np
import matplotlib
from matplotlib.animation import FuncAnimation
# Enter x and y coordinates of points and colors
a=(0,0.5);b=(0.43,-0.25);c=(-0.43,-0.25)
center=(0,0)
n = 3;r=1.0
theta = np.arange(0,360+(360/(n)),360/(n))
to=np.arange(0,2*np.pi,0.01)
x = r * np.cos(np.radians(theta))
y = r * np.sin(np.radians(theta))
xo = r * np.cos(to); yo = r * np.sin(to)
fig, ax = plt.subplots()
ax.plot(xo,yo)
# create artists: they will be used to update the position
# of the points being rendered
triangle, = ax.plot(x,y)
vertices = ax.scatter(x,y)
lim = r * 1.25
ax.set_xlim([-lim, lim]);ax.set_ylim([-lim, lim])
ax.set_aspect("equal")
w = 2
T = 2 * np.pi / w
# this defines the time steps of the animation
dt = np.linspace(0, 10 * T, num=500)
def animate(i):
x = r * np.cos(np.radians(theta) + w * dt[i])
y = r * np.sin(np.radians(theta) + w * dt[i])
# update the position of the points to be rendered
triangle.set_data(x, y)
vertices.set_offsets(np.stack([x, y]).T)
ax.set_title("Rotation #%s" % int(w * dt[i] / (2 * np.pi) + 1))
ani = FuncAnimation(fig, animate, frames=len(dt), repeat=False)
plt.show()
Check this out..
from IPython import display
import matplotlib.pyplot as plt
import numpy as np
import matplotlib
# Enter x and y coordinates of points and colors
a=(0,0.5);b=(0.43,-0.25);c=(-0.43,-0.25)
center=(0,0)
n = 3;r=1.0
theta = np.arange(0,360+(360/(n)),360/(n))
w = 2
T = 2*np.pi/w
dt = np.linspace(0, 10*T, num=10) #increase num for more finely distributed rotations.
for d in dt:
to=np.arange(0,2*np.pi,0.01)
x = r*np.sin(np.radians(theta + d))
y=r*np.cos(np.radians(theta + d))
xo=r*np.sin(to);yo=r*np.cos(to)
plt.plot(xo,yo)
plt.plot(x,y)
plt.scatter(x,y)
plt.xlim([-1, 1]);plt.ylim([-1,1])

Create subplots on the same page

How do I subplots multiple graphs? so it will look like the picture.
the image is how the plots should look
Im able to plot individule but i cant figure out
A = 1 # Wave amplitude in meters
T = 10 # Time Period in secs
pi = 3.14 # Value of pi
n_w = 10 # Number of waves
wavelength = 156 # Wavelength in meters
k = (2 * pi) / wavelength
w = (2 * pi) / T
def wave_elevation(x,t):
return A * np.cos((k * x) - (w * t))
t_list = np.array([0,0.25,0.5,0.75,1.0])*T
for t in t_list:
wave_ele_Val = []
for i in np.linspace(0,wavelength*n_w,1560):
wave_ele_Val.append(wave_elevation(i,t))
fig, ax = plt.subplots(figsize=(15, 5))
plt.plot(np.linspace(0,wavelength*n_w,1560),wave_ele_Val,'r')
plt.title("Wave Elevation-Space Variations # " + str(t) + "* Time Periods")
plt.xlabel("x (m)")
plt.ylabel("\u03B7")
plt.grid()
plt.show()
Try declaring figures outside loop.
import math
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
A = 1 # Wave amplitude in meters
T = 10 # Time Period in secs
pi = 3.14 # Value of pi
n_w = 10 # Number of waves
wavelength = 156 # Wavelength in meters
k = (2 * pi) / wavelength
w = (2 * pi) / T
def wave_elevation(x,t):
return A * np.cos((k * x) - (w * t))
x_list = np.array([0,0.25,0.5,0.75,1.0])*wavelength
fig, ax = plt.subplots(len(x_list), figsize=(15, 5))
for i, x in enumerate(x_list):
wave_ele_Val = []
for j in np.linspace(0,T*n_w,1000):
wave_ele_Val.append(wave_elevation(x, j))
ax[i].plot(np.linspace(0,T*n_w,1000),wave_ele_Val)
ax[i].grid()
plt.show()
all the configuration is in the link
You need to specify how many subplots you want:
matplotlib.pyplot.subplots(nrows=1, ncols=1, *, sharex=False, sharey=False, squeeze=True, subplot_kw=None, gridspec_kw=None, **fig_kw)
In your case this would be plt.subplots(5)
The plt.plot() needs to be changed to ax[i].plot(x,y)
Where i is your number of subplot.
Also shift the plt.show() outside of the loop, so it is called at the end and not in between.
This is one example, how you can do it:
x_list = np.array([0,0.25,0.5,0.75,1.0])*wavelength
fig, ax = plt.subplots(5, figsize=(15, 5))
for j,x in enumerate(x_list):
wave_ele_Val = []
for i in np.linspace(0,T*n_w,1000):
wave_ele_Val.append(wave_elevation(x, i))
ax[j].plot(np.linspace(0,T*n_w,1000),wave_ele_Val)
ax[j].grid()
ax[j].set_title("Wave Elevation-Time Variations # " + str(x) + "WaveLengths")
ax[j].set_ylabel("\u03B7")
fig.tight_layout()
plt.xlabel("Time (s)")
plt.show()
This gives me:

Animating a 3d vector - ValueError: too many values to unpack (expected 2)

I am trying to animate a rotating 3d vector. everything more or less works, expect my update-funtion for the "FuncAnimation"-part of the code. When I run the code, I get the following error message:
"Error in line "the line with the code "vector.set_data(u[i], v[i], w[i])" ValueError: too many values to unpack (expected 2)"
I have no idea what i am doing wrong, can anybody help?
from matplotlib import animation, rc
import numpy as np
from scipy.integrate import solve_ivp
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure(figsize=(10, 10))
ax = fig.gca(projection='3d')
t_end = 20
u0 = [1 / np.sqrt(2)]
v0 = [1 / np.sqrt(2)]
w0 = [0]
y0 = u0 + v0 + w0
print(y0)
def ode45(t, y):
u = np.array(y[0])
v = np.array(y[1])
w = np.array(y[2])
omega = np.pi / 2
delta = 0
dudt = delta * v
dvdt = -delta * u + omega * w
dwdt = - omega * v
return [dudt, dvdt, dwdt]
mysol = solve_ivp(ode45, [0, t_end], y0)
u = mysol.y[0]
v = mysol.y[1]
w = mysol.y[2]
r = np.mean(u ** 2 + v ** 2 + w ** 2)
print(r)
theta = np.linspace(0, 2 * np.pi, 101)
phi = np.linspace(0, np.pi, 101)
z = r * np.outer(np.ones(np.size(theta)), np.cos(phi))
x = r * np.outer(np.cos(theta), np.sin(phi))
y = r * np.outer(np.sin(theta), np.sin(phi))
ax.plot_surface(x, y, z, alpha=0.2, color='gray')
vector, = ax.plot([], [], [])
def update(i):
vector.set_data(u[i], v[i], w[i])
return vector
ax.plot([0], [0], [0], 'ro')
ax.plot(u, v, w, color='blue')
steps = 100 * t_end
anim = animation.FuncAnimation(fig, update, frames=t_end, interval=1, blit=True)
anim
plt.show()
This line is creating a tuple:
vector, = ax.plot([], [], [])
Pyplot .plot() returns a list (typically of lines or markers) to plot or adjust. I don't think it returns a tuple. So, in
def update(i):
vector.set_data(u[i], v[i], w[i])
return vector
The vector.set_data(u[i], v[i], w[i]) is calling set_data on a tuple of (ax.plot.lines, None). I think this might be the problem.
EDIT:
You should be able to fix it with this:
vector = ax.plot([], [], [])

matplotlib animation won't animate sine function

I'm trying to animate the function with matplotlib:
But for some reason, when I write it like that in the animate function:
l = 0.5
k = (2 * np.pi)/l
f = 4
w = 2 * np.pi * f
y = np.sin(k * x + w * i)
It doesn't animate, only when I write it with numbers it animates:
y = np.sin(15*x - 62 * i)
What is the reason? Why can't I use the other form?
Relevant code:
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation
fig = plt.figure()
ax = plt.axes(xlim=(0, 2), ylim=(-2, 2))
line, = ax.plot([], [], lw=2)
# initialization function
def init():
line.set_data([], [])
return line,
# animation function
def animate(i):
x = np.linspace(0, 2, 1000)
l = 0.5
k = (2 * np.pi)/l
f = 4
w = 2 * np.pi * f
y = np.sin(k * x + w * i)
#y = np.sin(15*x - 62 * i)
line.set_data(x, y)
return line,
anim = animation.FuncAnimation(fig, animate, init_func=init,
frames=300, interval=20, blit=True)
anim.save('basic_animation.mp4', fps=30, extra_args=['-vcodec', 'libx264'])
plt.show()
Thanks !!
The only problem is that your f is an integer and hence w is a multiple of 2 * np.pi. The function is essentially unchanged for integer i's. Change f to be non integer.

Matlab plot equivalent in Python [duplicate]

I'd like to plot pulse propagation in such a way at each step, it plots the pulse shape. In other words, I want a serie of x-z plots, for each values of y. Something like this (without color):
How can I do this using matplotlib (or Mayavi)? Here is what I did so far:
def drawPropagation(beta2, C, z):
""" beta2 in ps / km
C is chirp
z is an array of z positions """
T = numpy.linspace(-10, 10, 100)
sx = T.size
sy = z.size
T = numpy.tile(T, (sy, 1))
z = numpy.tile(z, (sx, 1)).T
U = 1 / numpy.sqrt(1 - 1j*beta2*z * (1 + 1j * C)) * numpy.exp(- 0.5 * (1 + 1j * C) * T * T / (1 - 1j*beta2*z*(1 + 1j*C)))
fig = pyplot.figure()
ax = fig.add_subplot(1,1,1, projection='3d')
surf = ax.plot_wireframe(T, z, abs(U))
Change to:
ax.plot_wireframe(T, z, abs(U), cstride=1000)
and call:
drawPropagation(1.0, 1.0, numpy.linspace(-2, 2, 10))
will create the following graph:
If you need the curve been filled with white color:
import numpy
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import pyplot
from matplotlib.collections import PolyCollection
def drawPropagation(beta2, C, z):
""" beta2 in ps / km
C is chirp
z is an array of z positions """
T = numpy.linspace(-10, 10, 100)
sx = T.size
sy = z.size
T = numpy.tile(T, (sy, 1))
z = numpy.tile(z, (sx, 1)).T
U = 1 / numpy.sqrt(1 - 1j*beta2*z * (1 + 1j * C)) * numpy.exp(- 0.5 * (1 + 1j * C) * T * T / (1 - 1j*beta2*z*(1 + 1j*C)))
fig = pyplot.figure()
ax = fig.add_subplot(1,1,1, projection='3d')
U = numpy.abs(U)
verts = []
for i in xrange(T.shape[0]):
verts.append(zip(T[i, :], U[i, :]))
poly = PolyCollection(verts, facecolors=(1,1,1,1), edgecolors=(0,0,1,1))
ax.add_collection3d(poly, zs=z[:, 0], zdir='y')
ax.set_xlim3d(numpy.min(T), numpy.max(T))
ax.set_ylim3d(numpy.min(z), numpy.max(z))
ax.set_zlim3d(numpy.min(U), numpy.max(U))
drawPropagation(1.0, 1.0, numpy.linspace(-2, 2, 10))
pyplot.show()

Categories

Resources