This example is taken from a tutorial related to convolution integral.
I would like to export this example as animation in mp4 format. So far, the code looks like this :
import scipy.integrate
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
def showConvolution(f1, f2, t0):
# Calculate the overall convolution result using Simpson integration
convolution = np.zeros(len(t))
for n, t_ in enumerate(t):
prod = lambda tau: f1(tau) * f2(t_-tau)
convolution[n] = scipy.integrate.simps(prod(t), t)
# Create the shifted and flipped function
f_shift = lambda t: f2(t0-t)
prod = lambda tau: f1(tau) * f2(t0-tau)
# Plot the curves
plt.gcf().clear() # il
plt.subplot(211)
plt.gca().set_ymargin(0.05) # il
plt.plot(t, f1(t), label=r'$f_1(\tau)$')
plt.plot(t, f_shift(t), label=r'$f_2(t_0-\tau)$')
plt.fill(t, prod(t), color='r', alpha=0.5, edgecolor='black', hatch='//') # il
plt.plot(t, prod(t), 'r-', label=r'$f_1(\tau)f_2(t_0-\tau)$')
plt.grid(True); plt.xlabel(r'$\tau$'); plt.ylabel(r'$x(\tau)$') # il
plt.legend(fontsize=10) # il
plt.text(-4, 0.6, '$t_0=%.2f$' % t0, bbox=dict(fc='white')) # il
# plot the convolution curve
plt.subplot(212)
plt.gca().set_ymargin(0.05) # il
plt.plot(t, convolution, label='$(f_1*f_2)(t)$')
# recalculate the value of the convolution integral at the current time-shift t0
current_value = scipy.integrate.simps(prod(t), t)
plt.plot(t0, current_value, 'ro') # plot the point
plt.grid(True); plt.xlabel('$t$'); plt.ylabel('$(f_1*f_2)(t)$') # il
plt.legend(fontsize=10) # il
plt.show() # il
Fs = 50 # our sampling frequency for the plotting
T = 5 # the time range we are interested in
t = np.arange(-T, T, 1/Fs) # the time samples
f1 = lambda t: np.maximum(0, 1-abs(t))
f2 = lambda t: (t>0) * np.exp(-2*t)
t0 = np.arange(-2.0,2.0, 0.05)
fig = plt.figure(figsize=(8,3))
anim = animation.FuncAnimation(fig, showConvolution(f1,f2, t0), frames=np.linspace(0, 50, 500), interval=80)
anim.save('animation.mp4', fps=30) # fps = frames per second
plt.show()
As I understood, I should be able to change t0 value between -2.00 and 2.00 with 0.05 steps. At first glance I've tried to use numpy's arange function.
t0 = np.arange(-2.0,2.0, 0.05)
But it gives an error message :
ValueError: operands could not be broadcast together with shapes (80,)
(500,)
How should I change t0 value so that I should be able to generate animation video?
Edit :
I tried the suggested changes. I run this example with
python convolution.py
Rather than an animation I see the output of see the output of convolution integral at t0 = -0.20.
Is there a way to change t0 so that I'd like to able to save it as animation as in the tutorial In the example t0 decreases from -2.0 to -1.95 etc the green curve is shifted right, and the area between curves, product increases. In the example there is an html animation and I would like to save as mp4 file.
Edit 2 :
Removing the plt.show() calls from inside of the re-draw function allows
it to run end-to-end and write out the animation.
It seems that the example is wrong.
The second argument in FuncAnimation takes a callable of which the first argument will get a new value from the 'frames' keyword argument every loop. Please take a look at the matplotlib documentation to find more information about the callable's required signature.
I simply changed the showConvolution() arguments around so that t0 is the first argument. The range t0 is used as the desired frames argument. The lambda functions f1 and f2 are passed in a tuple in 'fargs'.
Hope it helps you,
Cheers,
BdeG
import scipy.integrate
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
def showConvolution(t0,f1, f2):
# Calculate the overall convolution result using Simpson integration
convolution = np.zeros(len(t))
for n, t_ in enumerate(t):
prod = lambda tau: f1(tau) * f2(t_-tau)
convolution[n] = scipy.integrate.simps(prod(t), t)
# Create the shifted and flipped function
f_shift = lambda t: f2(t0-t)
prod = lambda tau: f1(tau) * f2(t0-tau)
# Plot the curves
plt.gcf().clear() # il
plt.subplot(211)
plt.gca().set_ymargin(0.05) # il
plt.plot(t, f1(t), label=r'$f_1(\tau)$')
plt.plot(t, f_shift(t), label=r'$f_2(t_0-\tau)$')
plt.fill(t, prod(t), color='r', alpha=0.5, edgecolor='black', hatch='//') # il
plt.plot(t, prod(t), 'r-', label=r'$f_1(\tau)f_2(t_0-\tau)$')
plt.grid(True); plt.xlabel(r'$\tau$'); plt.ylabel(r'$x(\tau)$') # il
plt.legend(fontsize=10) # il
plt.text(-4, 0.6, '$t_0=%.2f$' % t0, bbox=dict(fc='white')) # il
# plot the convolution curve
plt.subplot(212)
plt.gca().set_ymargin(0.05) # il
plt.plot(t, convolution, label='$(f_1*f_2)(t)$')
# recalculate the value of the convolution integral at the current time-shift t0
current_value = scipy.integrate.simps(prod(t), t)
plt.plot(t0, current_value, 'ro') # plot the point
plt.grid(True); plt.xlabel('$t$'); plt.ylabel('$(f_1*f_2)(t)$') # il
plt.legend(fontsize=10) # il
plt.show() # il
Fs = 50 # our sampling frequency for the plotting
T = 5 # the time range we are interested in
t = np.arange(-T, T, 1/Fs) # the time samples
f1 = lambda t: np.maximum(0, 1-abs(t))
f2 = lambda t: (t>0) * np.exp(-2*t)
t0 = np.arange(-2.0,2.0, 0.05)
fig = plt.figure(figsize=(8,3))
anim = animation.FuncAnimation(fig, showConvolution, frames=t0, fargs=(f1,f2),interval=80)
anim.save('animation.mp4', fps=30) # fps = frames per second
plt.show()
I have a quick implementation to visualize the convolution of two real functions defined with Sympy. The code outputs a .GIF though.
import sympy as sp
import numpy as np
import matplotlib.pyplot as plt
from sympy import lambdify
from matplotlib.animation import FuncAnimation
def symplot(t, F, interval, funLabel):
'''
Create plots of sympy symbolic functions
:param t: sympy variable
:param F: sympy function F(t)
:param interval: array of values of t where F should be evaluated [np.array]
:funLabel: curve label be displayed in the plot [string].
'''
fig = plt.figure()
if type(F) == list:
indLabel = 0
for f in F:
func = lambdify(t, f, modules=['numpy', {'Heaviside': lambda t:np.heaviside(t,0)}])
f_num = func(interval)
plt.plot(interval, f_num, label=funLabel[indLabel])
plt.legend();
plt.xlim([min(interval), max(interval)]);
plt.xlabel('tempo [s]');
indLabel += 1
else:
func = lambdify(t, F, modules=['numpy', {'Heaviside': lambda t:np.heaviside(t,0)}])
f_num = func(interval)
plt.plot(interval, f_num, label=funLabel)
plt.legend(loc="upper right");
plt.xlim([min(interval), max(interval)]);
plt.xlabel('tempo [s]');
plt.grid();
plt.close();
return fig
def genConvGIF(x, h, t, totalTime, ti, tf, figName, xlabel=[], ylabel=[], fram=200, inter=20, plotConv=False):
'''
Create and save a convolution plot animation as GIF
:param x: x(t) function [sympy expr]
:param h: h(t) function [sympy expr]
:param t: t time variable [sympy variable]
:param totalTime: array of time instants where the functions will be evaluated [nparray]
:param ti: time when animation starts [scalar]
:param tf: time when animation stops [scalar]
:param figName: figure file name w/ folder path [string]
:param xlabel: xlabel [string]
:param ylabel: ylabel [string]
:param fram: number of frames [int]
:param inter: time interval between frames [ms]
'''
x_func = lambdify(t, x, modules=['numpy', {'Heaviside': lambda t:np.heaviside(t,0)}])
h_func = lambdify(t, h, modules=['numpy', {'Heaviside': lambda t:np.heaviside(t,0)}])
x_num = x_func(totalTime)
h_num = h_func(totalTime)
dt = totalTime[1]-totalTime[0]
if plotConv:
y_num = np.convolve(h_num, x_num, 'same')*dt
ymax = np.max([x_num, h_num, y_num])
ymin = np.min([x_num, h_num, y_num])
else:
ymax = np.max([x_num, h_num])
ymin = np.min([x_num, h_num])
figAnim = plt.figure()
ax = plt.axes(xlim=(totalTime.min(), totalTime.max()),ylim=(ymin-0.1*np.abs(ymax), ymax+0.1*np.abs(ymax)))
line1, line2, line3 = ax.plot([], [], [], [], [], [])
line1.set_label(ylabel[0])
line2.set_label(ylabel[1])
if plotConv:
line3.set_label(ylabel[2])
ax.grid()
ax.legend(loc="upper right");
# plot static function
figh = symplot(t, h, totalTime, 'h(t)')
if len(xlabel):
plt.xlabel(xlabel)
def init():
line1.set_data(figh.get_axes()[0].lines[0].get_data())
return line1,
plt.close(figh)
delays = totalTime[::int(len(totalTime)/fram)]
ind = np.arange(0, len(totalTime), int(len(totalTime)/fram))
ind = ind[delays > ti]
delays = delays[delays > ti]
ind = ind[delays < tf]
delays = delays[delays < tf]
totalFrames = len(delays)
def animate(i):
figx = symplot(t, x.subs({t:delays[i]-t}), totalTime, 'x(t-τ)')
line2.set_data(figx.get_axes()[0].lines[0].get_data())
if plotConv:
line3.set_data(totalTime[0:ind[i]], y_num[0:ind[i]])
plt.close(figx)
return line2, line3
anim = FuncAnimation(figAnim, animate, init_func=init, frames=totalFrames, interval=inter, blit=True)
anim.save(figName, dpi=200, writer='imagemagick')
plt.close()
example of .GIF generated by the code
You can find a notebook with a quick tutorial of how to use it here:
https://github.com/edsonportosilva/ElectricCircuits/blob/master/Jupyter%20notebooks/Visualize%20convolution.ipynb
Related
I have a code to make about the 2D schrodinger equation time dependant. I was able to figure how to use the finites differences and I guess I was able to solve the 1D schrodinger equation. But know I have to plot my wave function in spherical coordinate (so in 2D?) and create an animation to observe a wave packet at certain energies (3.48 Hartree). It is suggested that E=k^2/2 So I used this to make my schrodinger equation energy dependant. The potential and deltak are given. I also need to make the wave packet propagatinf from r=15 to r=0, I think that I just need to insert a minus in my exponential in my psi0 which I did in the code below. Any idea or even explanation would be welcome
import numpy as np
from scipy import sparse
import matplotlib.pyplot as plt
import scipy.integrate as integrate
from matplotlib.animation import FuncAnimation
from matplotlib import animation
from IPython import display
dx = 0.02 # spatial separation
a= 15
x = np.arange(0.1, a, dx) # spatial grid points
deltak = 0.2 # center of initial gaussian wave-packet
E=3.48
x0= 2
A=1.0 / (deltak * np.sqrt(np.pi)) # normalization constant
hbar = 1
dt = 0.1 # time interval for snapshots
t0 = 0.0 # initial time
tf = 1.0 # final time
t_eval = np.arange(t0, tf, dt)
k = np.sqrt(2 * E)
Vx= 7.5 * x**2 * np.exp(-x)
def psi_t2(t,psi):
return (-1j * (((-0.5 * D2.dot(psi)) + V * psi)))
# Initial Wavefunction
psi0_ = np.sqrt(A) * np.exp(-(x-x0)**2 / (2.0 * deltak**2)) * np.exp(1j * -k * x)
# Solve the Initial Value Problem
sol_ = integrate.solve_ivp(psi_t2, t_span = [t0, tf], y0 = psi0_, t_eval = t_eval,method="RK23")
for i,t in enumerate (sol_.t):
plt.plot(x, np.abs(sol_.y[:,i])**2)
fig=plt.figure()
ax=plt.subplot(1,1,1)
#fig,ax = plt.subplots(figsize=(8,4))
ax.set_xlim(-5, 16)
ax.set_ylim(0, 5)
title = ax.set_title('')
line1, = ax.plot([], [], "k--")
line2, = ax.plot([], [])
def init():
line1.set_data(x, V)
return line1,
def animate(i):
line2.set_data(x, np.abs(sol_.y[:,i])**2)
#line2.set_data(x, np.real(sol.y[:, i]))
#line2.set_data(x, np.abs(psi))
title.set_text('Time = {0:1.3f}'.format(sol_.t[i])) #permet d'afficher le temps
return line1,
anim = animation.FuncAnimation(fig, animate, init_func=init,frames=len(sol_.t), interval=50, blit=True)
video = anim.to_html5_video()
html = display.HTML(video)
display.display(html)
plt.close()
This example is taken from a tutorial and this post related to convolution integral.
I would like to show it in a jupyter notebook using animation from matplotlib. I had a look at this stack post. So far, the code looks like this:
import scipy.integrate
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
plt.rcParams["animation.html"] = "jshtml"
plt.rcParams['figure.dpi'] = 150
plt.ioff()
def showConvolution(t0, f1, f2):
# Calculate the overall convolution result using Simpson integration
convolution = np.zeros(len(t))
for n, t_ in enumerate(t):
prod = lambda tau: f1(tau) * f2(t_-tau)
convolution[n] = scipy.integrate.simps(prod(t), t)
# Create the shifted and flipped function
f_shift = lambda t: f2(t0-t)
prod = lambda tau: f1(tau) * f2(t0-tau)
# Plot the curves
plt.subplot(211)
plt.plot(t, f1(t), label=r'$f_1(\tau)$')
plt.plot(t, f_shift(t), label=r'$f_2(t_0-\tau)$')
plt.plot(t, prod(t), 'r-', label=r'$f_1(\tau)f_2(t_0-\tau)$')
# plot the convolution curve
plt.subplot(212)
plt.plot(t, convolution, label='$(f_1*f_2)(t)$')
# recalculate the value of the convolution integral at the current time-shift t0
current_value = scipy.integrate.simps(prod(t), t)
plt.plot(t0, current_value, 'ro') # plot the point
Fs = 50 # our sampling frequency for the plotting
T = 5 # the time range we are interested in
t = np.arange(-T, T, 1/Fs) # the time samples
f1 = lambda t: np.maximum(0, 1-abs(t))
f2 = lambda t: (t>0) * np.exp(-2*t)
t0 = np.arange(-2.0,2.0, 0.05)
fig = plt.figure(figsize=(8,3))
anim = animation.FuncAnimation(fig, showConvolution, frames=t0, fargs=(f1,f2),interval=80)
anim
Now I get a quite poor loking animation instead:
I modified the SO answer in the question to an animation that works in jupyter and only required code for your code, and changed it to the axes format since I have no experience with pyplot format animations. The issue is due to the removal of the clearing of the graph. `axes[0].clear() is there to remove the previous graph element.
import scipy.integrate
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
def showConvolution(t0,f1, f2):
# Calculate the overall convolution result using Simpson integration
convolution = np.zeros(len(t))
for n, t_ in enumerate(t):
prod = lambda tau: f1(tau) * f2(t_-tau)
convolution[n] = scipy.integrate.simps(prod(t), t)
# Create the shifted and flipped function
f_shift = lambda t: f2(t0-t)
prod = lambda tau: f1(tau) * f2(t0-tau)
# Plot the curves
axes[0].clear() # il
axes[1].clear()
axes[0].set_xlim(-5, 5)
axes[0].set_ylim(0, 1.0)
#axes[0].set_ymargin(0.05) # il
axes[0].plot(t, f1(t), label=r'$f_1(\tau)$')
axes[0].plot(t, f_shift(t), label=r'$f_2(t_0-\tau)$')
#axes[0].fill(t, prod(t), color='r', alpha=0.5, edgecolor='black', hatch='//') # il
axes[0].plot(t, prod(t), 'r-', label=r'$f_1(\tau)f_2(t_0-\tau)$')
#axes[0].grid(True); axes[0].set_xlabel(r'$\tau$'); axes[0].set_ylabel(r'$x(\tau)$') # il
#axes[0].legend(fontsize=10) # il
#axes[0].text(-4, 0.6, '$t_0=%.2f$' % t0, bbox=dict(fc='white')) # il
# plot the convolution curve
axes[1].set_xlim(-5, 5)
axes[1].set_ylim(0, 0.4)
#axes[1].set_ymargin(0.05) # il
axes[1].plot(t, convolution, label='$(f_1*f_2)(t)$')
# recalculate the value of the convolution integral at the current time-shift t0
current_value = scipy.integrate.simps(prod(t), t)
axes[1].plot(t0, current_value, 'ro') # plot the point
#axes[1].grid(True); axes[1].set_xlabel('$t$'); axes[1].set_ylabel('$(f_1*f_2)(t)$') # il
#axes[1].legend(fontsize=10) # il
#plt.show() # il
Fs = 50 # our sampling frequency for the plotting
T = 5 # the time range we are interested in
t = np.arange(-T, T, 1/Fs) # the time samples
f1 = lambda t: np.maximum(0, 1-abs(t))
f2 = lambda t: (t>0) * np.exp(-2*t)
t0 = np.arange(-2.0,2.0, 0.05)
fig = plt.figure(figsize=(8,3))
axes= fig.subplots(2, 1)
anim = animation.FuncAnimation(fig, showConvolution, frames=t0, fargs=(f1,f2),interval=80)
#anim.save('animation.mp4', fps=30) # fps = frames per second
#plt.show()
from IPython.display import HTML
plt.close()
HTML(anim.to_html5_video())
I am trying to plot an animation of a simple pendulum
using the model https://matplotlib.org/gallery/animation/double_pendulum_sgskip.html.
My code is as follows :
from numpy import sin, cos
import numpy as np
import matplotlib.pyplot as plt
import scipy.integrate as integrate
import matplotlib.animation as animation
#some constants
g = 9.81
l = 0.1
m = 0.01
def sh(r,t):
theta = r[0]
omega = r[1]
sh_theta = omega
sh_omega = -g/l*sin(theta)
return np.array([sh_theta,sh_omega],float)
init_state = [np.radians(89.0),0]
time = np.arange(0,50.0,0.025)
time_elapsed = time
def step_solver(eq, ist, dt):
"""
Execute one time step of length dt and update status
"""
global time_elapsed
state1,state2 = integrate.odeint(eq,ist,[0,dt])
time_elapsed += dt
return state1, state2,time_elapsed
dt = 1/30
ysol,ysolv,timex = step_solver(sh,init_state,dt)
print("This is the y0 values: ", ysol,"y values",ysolv,"This is the time ", timex)
##===================================
##Setting up figure and animation
#======================================
fig = plt.figure()
ax = plt.axes(xlim = (0,2), ylim = (-2,2))
line, = ax.plot([],[],lw=2)
#time_text = ax.text(0.02,0.95,'',transform = ax.transAxes)
#==========================================
##initialisation function: plot the background of each frame
def init():
line.set_data([],[])
#time_text.set_text('')
return line,
def animate(ysol,timex):
x = timex
y = ysol
line.set_data(x,y)
#time_text.set_text(str(i))
return line,
#================================================
#Call the animator
#================================================
anim = animation.FuncAnimation(fig,animate(ysolv,timex), init_func = init, frames = 200, interval =20, blit = True)
anim.save('basic_animation.mp4', fps=30, extra_args=['-vcodec', 'libx264'])
plt.show()
EDIT :
I am getting the error message :
ValueError: shape mismatch: objects cannot be broadcast to a single shape
<Figure size 432x288 with 1 Axes>
I have checked what my function step_solver is printing with
print(len(ysol),len(ysolv),len(timex))
and after recommendation the other y output for odeint which gave only 2 values for my ysol and ysolv variable for 2200 time values.
I was expecting to get a range of y values for each time step.
I am not sure how to sort this. Is my function step_solver wrongly coded?
Why am I only getting 2 values, how can I animate the solution in the same way it was done for the double pendulum?
Any suggestions on where the problem may lie?
Many thanks in advance.
Let's follow the code from the example more closely. Which means to use just one integration call and then using slices of the result of that call in the animation.
from numpy import sin, cos
import numpy as np
import matplotlib.pyplot as plt
import scipy.integrate as integrate
import matplotlib.animation as animation
#some constants
g = 9.81
l = 0.1
m = 0.01
def sh(r,t):
theta, omega = r
sh_theta = omega
sh_omega = -g/l*sin(theta)
return np.array([sh_theta,sh_omega],float)
init_state = np.radians([89.0,0])
dt = 1.0/30
time = np.arange(0,50.0,dt)
state = integrate.odeint(sh,init_state,time)
##===================================
##Setting up figure and animation
#======================================
fig = plt.figure()
ax = plt.axes(xlim = (0,10), ylim = (-2,2))
line, = ax.plot([],[],lw=2)
#==========================================
##initialisation function: plot the background of each frame
def init():
return line,
def animate(i):
x = time[i:i+30]
y = state[i:i+30,0]
line.set_data(x,y)
return line,
#================================================
#Call the animator
#================================================
anim = animation.FuncAnimation(fig,animate, init_func = init, frames = 200, interval =20, blit = True)
plt.show()
For a variant using a step generator using yield see my answer in Error in RK4 algorithm in Python. This allows to encapsulate the data for the integration loop without defining a class for it. However it is not clear how a function graph with two samples would be helpful, even if it is animated.
To animate the pendulum itself, use
##===================================
##Setting up figure and animation
#======================================
fig = plt.figure(figsize=(8,6))
ax = plt.axes(xlim = (-2*l,2*l), ylim = (-2*l,l))
line, = ax.plot([],[],'-o',lw=2,ms=8)
#==========================================
##initialisation function: plot the background of each frame
def init():
return line,
def animate(i):
phi = state[i,0]
line.set_data([0,l*sin(phi)],[0,-l*cos(phi)])
return line,
#================================================
#Call the animator
#================================================
anim = animation.FuncAnimation(fig,animate, init_func = init, frames = len(time), interval =100, blit = True)
plt.show()
I want to create an animation showing a diver jumps into water.
By the given parameters of original height of diver from the water, h and his mass, m, I defined a procedure in Python to calculate the moment he touches the water, Tc .
Knowing that he jumps vertically, X axis is fixed, and
Y axis obeys equation (1/2)gt^2 + h (g is gravitational constant)
How do I plot a graph while time t is in range(Tc), X and Y axis shows the projection the diver? (x is fixed and y depends on time t)
In the graphic window we are supposed to see a dot that 'jumps' from certain height vertically downwards, without seeing the line/trace of projection.
Here is part of my work. I don't know where to introduce Tc in the procedure:
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation
# First set up the figure, the axis, and the plot element we want to animate
fig = plt.figure()
ax = plt.axes(xlim=(0, 2), ylim=(-2, 2))
line, = ax.plot([], [], lw=2)
# initialization function: plot the background of each frame
def init():
line.set_data([], [])
return line,
# animation function. This is called sequentially
def animate(i):
x = np.empty(n) ; x.fill(1) # the vertical position is fixed on x-axis
y = 0.5*g*i^2 + h # the equation of diver's displacement on y axis
line.set_data(x, y)
return line,
# call the animator. blit=True means only re-draw the parts that have changed.
anim = animation.FuncAnimation(fig, animate, init_func=init,
frames=200, interval=20, blit=True)
plt.show()
Edit:
Here is the whole program. I applied and modified the suggestion given by #Mike Muller, but it didn't work. I don’t understand where it goes wrong. Hope you can clarify my doubts.
# -*- coding: utf-8 -*-
from math import *
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation
def Plongeon():
h = input("height = ")
h = float(h)
m = input(" mass = ")
m = float(m)
global g
g = 9.8
g = float(g)
global Tc #calculate air time, Tc
Tc = sqrt(2*h/g)
Tc = round(Tc,2)
print Tc
# First set up the figure, the axis, and the plot element we want to animate
fig = plt.figure()
ax = plt.axes(xlim=(0, 2), ylim=(-2, h+1)) #ymax : initial height+1
line, = ax.plot([], [], ' o', lw=2)
Tc = int(Tc+1) #make Tc an integer to be used later in def get_y()
xs = [1] # the vertical position is fixed on x-axis
ys = [h, h]
# initialization function: plot the background of each frame
def init():
line.set_data([], [])
return line,
# animation function. This is called sequentially
def animate(y):
ys[-1] = y
line.set_data(xs, ys)
return line,
def get_y():
for step in range(Tc):
t = step / 100.0
y = -0.5*g*t**2 + h # the equation of diver's displacement on y axis
yield y
# call the animator. blit=True means only re-draw the parts that have changed.
anim = animation.FuncAnimation(fig, animate, frames=get_y, interval=100)
plt.show()
Plongeon()
Answer based on original question
You need to use a generator to produce your y data. This works:
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation
# First set up the figure, the axis, and the plot element we want to animate
fig = plt.figure()
ax = plt.axes(xlim=(0, 2), ylim=(-2, 2))
line, = ax.plot([], [], ' o', lw=2)
g = 9.81
h = 2
tc = 200
xs = [1] # the vertical position is fixed on x-axis
ys = [h, h]
# animation function. This is called sequentially
def animate(y):
ys[-1] = y
line.set_data(xs, ys)
return line,
def get_y():
for step in range(tc):
t = step / 100.0
y = -0.5*g*t**2 + h # the equation of diver's displacement on y axis
yield y
# call the animator. blit=True means only re-draw the parts that have changed.
anim = animation.FuncAnimation(fig, animate, frames=get_y, interval=100)
plt.show()
Integrated answer
This should work:
# -*- coding: utf-8 -*-
from math import *
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation
def Plongeon():
h = float(input("height = "))
g = 9.81
#calculate air time, Tc
Tc = sqrt(2 * h / g)
# First set up the figure, the axis, and the plot element we want to animate
fig = plt.figure()
ax = plt.axes(xlim=(0, 2), ylim=(-2, h+1)) #ymax : initial height+1
line, = ax.plot([], [], ' o', lw=2)
step = 0.01 # animation step
xs = [1] # the vertical position is fixed on x-axis
ys = [h]
# animation function. This is called sequentially
def animate(y):
ys[-1] = y
line.set_data(xs, ys)
return line,
def get_y():
t = 0
while t <= Tc:
y = -0.5 * g * t**2 + h # the equation of diver's displacement on y axis
yield y
t += step
# call the animator. blit=True means only re-draw the parts that have changed.
anim = animation.FuncAnimation(fig, animate, frames=get_y, interval=100)
plt.show()
Plongeon()
I removed unneeded lines. No need for global. Also mass has never been used anywhere in the program.
This is the most important part:
def get_y():
t = 0
while t <= Tc:
y = -0.5 * g * t**2 + h
yield y
t += step
You need to advance your time by an increment.
My code has been modified according to many great suggestions from people in this forum. However, I still have some questions about the code.
My code is:
from pylab import *
from numpy import *
N = 100 #lattice points per axis
dt = 1 #time step
dx = 1 #lattice spacing
t = arange(0, 1000000*dt, dt) #time
a = 1 #cofficient
epsilon = 100 #cofficient
M = 1.0 #cofficient
every = 100 #dump an image every
phi_0 = 0.5 #initial mean value of the order parameter
noise = 0.1 #initial amplitude of thermal fluctuations in the order parameter
th = phi_0*ones((N, N)) + noise*(rand(N, N) - 0.5) #initial condition
x, y = meshgrid(fftfreq(int(th.shape[0]), dx), fftfreq(int(th.shape[1]), dx))
k2 = (x*x + y*y) #k is a victor in the Fourier space, k2=x^2+y^2
g = lambda th, a: 4*a*th*(1-th)*(1-2*th) #function g
def update(th, dt, a, k2):
return ifft2((fft2(th)-dt*M*k2*fft2(g(th,a)))/(1+2*epsilon*M*dt*k2**2))
for i in range(size(t)):
print t[i]
if mod(i, every)==0:
imshow(abs(th), vmin=0.0, vmax=1.0)
colorbar()
show()
#savefig('t'+str(i/every).zfill(3)+'.png', dpi=100)
clf()
th=update(th, dt, a, k2)
When I run it, I have to close the figures one by one to see the changes. But I want to demonstrate the changes of the images in one figure. Any good ideas?
Use the "animation" feature of matplotlib, like in
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
def update_line(num, data, line):
line.set_data(data[...,:num])
return line,
fig1 = plt.figure()
data = np.random.rand(2, 25)
l, = plt.plot([], [], 'r-')
plt.xlim(0, 1)
plt.ylim(0, 1)
plt.xlabel('x')
plt.title('test')
line_ani = animation.FuncAnimation(fig1, update_line, 25, fargs=(data, l),
interval=50, blit=True)
plt.show()
Tutorial at :
http://matplotlib.org/1.3.1/examples/animation/index.html