How to show the changes of multiple images in one figure? - python

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

Related

Plotting 2D Schrodinger equation on Python and be able to see a resonance at certain energy

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

How to plot the graph of a function depending of time and space

We consider the following funtion depending of $t$ and $x$:
$f(t,x) = e^{-4t\pi^2}\sin(\pi x)$
So, for each time $t$ in the list [0., 0.025, 0.05 , 0.075, 0.1] I would like to plot the graph of the function f(t,.) in Python.
I have tried the following code:
import numpy as np
import matplotlib.pyplot as plt
'time discretization'
dt = 0.025
t = np.arange(0, 0.1 + dt, dt)
m = len(t)
'space discretization'
dx = 0.025
x = np.arange(0, 1 + dx, dx)
n = len(x)
'Matrix E'
E = np.zeros((n,m))
'Loop'
for j in range(0,m-1):
E[:, j ] = np.exp(-4jnp.pi**2)np.sin(np.pix)
'Graphic'
plt.plot(E)
plt.legend([f't = {value}s' for value in t])
However, with the exception of $t = 0$ the graphs displayed after I run the code are completely wrong.
Does some of you have some idea or know some tutorial that can help me to solve this problem?
I thank you in advance for the answer.
I think you might have a couple problems---one main thing is that when calling plt.plot, you generally want to supply x and y coordinates. Also, you are generating 41 values for x, and 5 values for t, which might lead to issues. But, maybe something like this is what you want?
import numpy as np
import matplotlib.pyplot as plt
def f(t, x):
return np.exp(-4 * t * np.pi ** 2) * np.sin(np.pi * x)
# creating the data
dt = 0.025
t = np.arange(0, 0.1 + dt, dt)
m = len(t)
dx = 0.025
x = np.arange(0, 1 + dx, dx)
# making the plot
plt.figure(figsize=(10, 5))
plt.plot(x, f(0, x), label='t = 0')
for i in range(1, m):
plt.plot(x, f(t[i], x), label=f't = {f[i]}')
plt.xlabel('x')
plt.ylabel('f(t, x)')
plt.legend()
plt.show()

Convolution integral export as animation in jupyter

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

3D scatter plot animation

I am trying to create a 3D animation scatter plot where each point is plotted as a sphere with radius of r proportional to value M (please see the code below), I guess it should be done by using argument s in ax.scatter, but since this value is unique for each (x,y,z), I don't know how to pass that to graph._offsets3d which accepts (x,y,z) touple. This is the first part of the task, the other part is that the data should appear at their specific time t (please see the code below).
I am currently struggling to change the size of each point according to their corresponding value in M, and color code the point with its corresponding time t, do you know how could I do this?
It would my next task to add a play/pause button to the figure and be able to rotate the the graph?
Does anyone have similar experiences that I could benefit from?
Many thanks!
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.animation as animation
#####Data Generation####
# Space Coordinate
X = np.random.random((100,)) * 255 * 2 - 255
Y = np.random.random((100,)) * 255 * 2 - 255
Z = np.random.random((100,)) * 255 * 2 - 255
# Magnitude of each point
M = np.random.random((100,))*-1+0.5
# Time
t = np.sort(np.random.random((100,))*10)
#ID each point should be color coded. Moreover, each point belongs to a cluster `ID`
ID = np.sort(np.round([np.random.random((100,))*5]))
def update_lines(num):
for i in range (df_IS["EASTING [m]"].size):
dx = X[i]
dy = Y[i]
dz = Z[i]
text.set_text("{:d}: [{:.0f}] Mw[{:.2f}]".format(ID[i], t[i],ID[i])) # for debugging
x.append(dx)
y.append(dy)
z.append(dz)
graph._offsets3d = (x, y, z)
return graph,
fig = plt.figure(figsize=(5, 5))
ax = fig.add_subplot(111, projection="3d")
graph = ax.scatter(X, Y, Z, color='orange') # s argument here
text = fig.text(0, 1, "TEXT", va='top') # for debugging
ax.set_xlim3d(X.min(), X.max())
ax.set_ylim3d(Y.min(), Y.max())
ax.set_zlim3d(Z.min(),Z.max())
# Creating the Animation object
ani = animation.FuncAnimation(fig, update_lines, frames=200, interval=500, blit=False)
plt.show()
In the animation function was looped by the size of the data frame, but rewrote your code partly because the animation argument is linked to the number of frames. Please correct me if I'm wrong. You can also pass in the size with graph.set_sizes(), which you can specify there. Your size variable had a negative value, so I'm recreating it as an integer. I've used a separate library in part because of my working environment.
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.animation as animation
from IPython.display import HTML # Animation on jupyter lab
from matplotlib.animation import PillowWriter # For GIF animation
#####Data Generation####
# Space Coordinate
X = np.random.random((100,)) * 255 * 2 - 255
Y = np.random.random((100,)) * 255 * 2 - 255
Z = np.random.random((100,)) * 255 * 2 - 255
# Magnitude of each point
# M = np.random.random((100,))*-1+0.5
M = np.random.randint(1,70, size=100)
# Time
t = np.sort(np.random.random((100,))*10)
#ID each point should be color coded. Moreover, each point belongs to a cluster `ID`
ID = np.sort(np.round([np.random.random((100,))*5]))
x = []
y = []
z = []
m = []
def update_lines(i):
# for i in range (df_IS["EASTING [m]"].size):
dx = X[i]
dy = Y[i]
dz = Z[i]
dm = M[i]
# text.set_text("{:d}: [{:.0f}] Mw[{:.2f}]".format(ID[i], t[i],ID[i])) # for debugging
x.append(dx)
y.append(dy)
z.append(dz)
m.append(dm)
graph._offsets3d = (x, y, z)
graph.set_sizes(m)
return graph,
fig = plt.figure(figsize=(5, 5))
ax = fig.add_subplot(111, projection="3d")
graph = ax.scatter(X, Y, Z, s=M, color='orange') # s argument here
text = fig.text(0, 1, "TEXT", va='top') # for debugging
ax.set_xlim3d(X.min(), X.max())
ax.set_ylim3d(Y.min(), Y.max())
ax.set_zlim3d(Z.min(), Z.max())
# Creating the Animation object
ani = animation.FuncAnimation(fig, update_lines, frames=100, interval=500, blit=False, repeat=False)
# plt.show()
ani.save('test3Dscatter.gif', writer='pillow')
plt.close()
HTML(ani.to_html5_video())
Edit:
# Time
t = np.sort(np.random.random((100,))*10)
# datapoint for color
cm_name = 'jet'
cm = plt.get_cmap(cm_name, 100)
C = [cm(n) for n in range(cm.N)]
# list for colors add
x = []
y = []
z = []
m = []
c = []
# animation function update
dm = M[i]
dc = C[i] # update
m.append(dm)
c.append(dc) # update
graph._facecolor3d = c # scatter color defined
return graph,

Matplotlib animation in real time

In the example below I want to make an animation where a point moves around a circle in T seconds (for example T=10). However it is a lot slower and doesn't work. So, what is wrong with my code and how to fix it? As far as I understand the api (http://matplotlib.org/api/animation_api.html) setting interval=1 should update the figure every millisecond.
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation
R = 3
T = 10
fig = plt.figure()
fig.set_dpi(300)
fig.set_size_inches(7, 6.5)
ax = plt.axes(xlim=(-10, 10), ylim=(-R*1.5, R*1.5))
ax.set_aspect('equal')
patch = plt.Circle((0, 0), 0.1, fc='r')
looping = plt.Circle((0,0),R,color='b',fill=False)
ax.add_artist(looping)
time_text = ax.text(-10,R*1.2,'',fontsize=15)
def init():
time_text.set_text('')
patch.center = (0, 0)
ax.add_patch(patch)
return patch,time_text,
def animate(i):
t=i/1000.0
time_text.set_text(t)
x, y = patch.center
x = R*np.sin(t/T*2*np.pi)
y = R*np.cos(t/T*2*np.pi)
patch.center = (x, y)
return patch,time_text
slow_motion_factor=1
anim = animation.FuncAnimation(fig, animate,
init_func=init,
frames=10000,
interval=1*slow_motion_factor,
blit=True)
plt.show()
I should add that the problem depends on the machine where I run the program. For example on a old Intel dualcore (P8700) (that's the box where the program should run), it is considerable slower than on a newer haswell i7 desktop cpu. But in the latter case it is also much slower as intended.
The problem is, that your computer is not fast enough, to deliver a new image every 1 ms. Which is kind of expected.
You should go for a more realistic speed. 25 frames per second should be enough
and also be possible to render in time.
I also made a few adjustment to you code, mostly style and more semantic variable names.
The biggest change was adapting this answer to your code to get rid of the first frame being still there after the init:
Matplotlib animation: first frame remains in canvas when using blit
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation
R = 3
T = 10
time = 3 * T
slow_motion_factor = 1
fps = 50
interval = 1 / fps
fig = plt.figure(figsize=(7.2, 7.2))
ax = fig.add_subplot(1, 1, 1, aspect='equal')
ax.set_xlim(-1.5 * R, 1.5 * R)
ax.set_ylim(-1.5 * R, 1.5 * R)
runner = plt.Circle((0, 0), 0.1, fc='r')
circle = plt.Circle((0, 0), R, color='b', fill=False)
ax.add_artist(circle)
time_text = ax.text(1.1 * R, 1.1 * R,'', fontsize=15)
def init():
time_text.set_text('')
return time_text,
def animate(i):
if i == 0:
ax.add_patch(runner)
t = i * interval
time_text.set_text('{:1.2f}'.format(t))
x = R * np.sin(2 * np.pi * t / T)
y = R * np.cos(2 * np.pi * t / T)
runner.center = (x, y)
return runner, time_text
anim = animation.FuncAnimation(
fig,
animate,
init_func=init,
frames=time * fps,
interval=1000 * interval * slow_motion_factor,
blit=True,
)
plt.show()

Categories