Matplotlib FuncAnimation not displaying any frames until animation is complete - python

I'm trying to animate a plot using matplotlib's FuncAnimation, however no frames of the animation are visible until the animation reaches the final frame. If I set repeat = True nothing is ever displayed. When I first run the code a matplotlib icon appears but nothing displays when I click on it until it shows me the final frame:
If I save the animation I see the animation display correctly so this leads me to think that my code is mostly correct so I hope this is a simple fix that I'm just missing.
Apologies if I'm dumping too much code but I'm not sure if there's anything that's not needed for the minimum reproducible example.
Here's the main code
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from quantum_custom.constants import spin_down, spin_up, H00, H11, H
import quantum_custom.walk as walk
class QuantumState:
def __init__(self, state):
self.state = state
#"coin flips"
max_N = 100 #this will be the final number of coin flips
positions = 2*max_N + 1
#initial conditions
initial_spin = spin_down
initial_position = np.zeros(positions)
initial_position[max_N] = 1
initial_state = np.kron(np.matmul(H, initial_spin), initial_position) #initial state is Hadamard acting on intial state, tensor product with the initial position
quantum_state = QuantumState(initial_state)
#plot the graph
fig, ax = plt.subplots()
plt.title("N = 0")
x = np.arange(positions)
line, = ax.plot([],[])
loc = range(0, positions, positions // 10)
plt.xticks(loc)
plt.xlim(0, positions)
plt.ylim((0, 1))
ax.set_xticklabels(range(-max_N, max_N + 1, positions // 10))
ax.set_xlabel("x")
ax.set_ylabel("Probability")
def init():
line.set_data([],[])
return line,
def update(N):
next_state = walk.flip_once(quantum_state.state, max_N)
probs = walk.get_prob(next_state, max_N)
quantum_state.state = next_state
start_index = N % 2 + 1
cleaned_probs = probs[start_index::2]
cleaned_x = x[start_index::2]
line.set_data(cleaned_x, cleaned_probs)
if cleaned_probs.max() != 0:
plt.ylim((0, cleaned_probs.max()))
plt.title(f"N = {N}")
return line,
anim = animation.FuncAnimation(
fig,
update,
frames = max_N + 1,
init_func = init,
interval = 20,
repeat = False,
blit = True,
)
anim.save("animated.gif", writer = "ffmpeg", fps = 15)
plt.show()
Here's my quantum_custom.constants module.
#define spin up and spin down vectors as standard basis
spin_up = np.array([1,0])
spin_down = np.array([0,1])
#define our Hadamard operator, H, in terms of ith, jth entries, Hij
H00 = np.outer(spin_up, spin_up)
H01 = np.outer(spin_up, spin_down)
H10 = np.outer(spin_down, spin_up)
H11 = np.outer(spin_down, spin_down)
H = (H00 + H01 + H10 - H11)/np.sqrt(2.0) #matrix representation of Hadamard gate in standard basis
Here's my quantum_custom.walk module.
import numpy as np
from quantum_custom.constants import H00, H11, H
#define walk operators
def walk_operator(max_N):
position_count = 2 * max_N + 1
shift_plus = np.roll(np.eye(position_count), 1, axis = 0)
shift_minus = np.roll(np.eye(position_count), -1, axis = 0)
step_operator = np.kron(H00, shift_plus) + np.kron(H11, shift_minus)
return step_operator.dot(np.kron(H, np.eye(position_count)))
def flip_once(state, max_N):
"""
Flips the Hadamard coin once and acts on the given state appropriately.
Returns the state after the Hadamard coin flip.
"""
walk_op = walk_operator(max_N)
next_state = walk_op.dot(state)
return next_state
def get_prob(state, max_N):
"""
For the given state, calculates the probability of being in any possible position.
Returns an array of probabilities.
"""
position_count = 2 * max_N + 1
prob = np.empty(position_count)
for k in range(position_count):
posn = np.zeros(position_count)
posn[k] = 1
posn_outer = np.outer(posn, posn)
alt_measurement_k = eye_kron(2, posn_outer)
proj = alt_measurement_k.dot(state)
prob[k] = proj.dot(proj.conjugate()).real
return prob
def eye_kron(eye_dim, mat):
"""
Speeds up the calculation of the tensor product of an identity matrix of dimension eye_dim with a given matrix.
This exploits the fact that majority of values in the resulting matrix will be zeroes apart from on the leading diagonal where we simply have copies of the given matrix.
Returns a matrix.
"""
mat_dim = len(mat)
result_dim = eye_dim * mat_dim #dimension of the resulting matrix
result = np.zeros((result_dim, result_dim))
result[0:mat_dim, 0:mat_dim] = mat
result[mat_dim:result_dim, mat_dim:result_dim] = mat
return result
I know that saving the animation is a solution but I'd really like to have the plot display just from running the code as opposed to having to save it. Thanks!

As per Sameeresque's suggestion I tried using different backends for matplot lib. This was done by altering by import statements as follows.
import matplotlib
matplotlib.use("tkagg")
import matplotlib.pyplot as plt
Note that it's important to add the two additional lines before import matplotlib.pyplot as plt otherwise it won't do anything.

Related

Animation was deleted without rendering anything. This is most likely unintended?

I'm wondering, what is wrong with this code that tries to reproduce a animated version of Mandelbrot fractals. I think the structure-wise, it should be ok, since I can get a static plot without the animation part, but when I try to run it with animation to perform iterations, it give me error.
Upon execution of the code, I got UserWarning: Animation was deleted without rendering anything. This is most likely unintended. To prevent deletion, assign the Animation to a variable that exists for as long as you need the Animation.
but apparently a variable is assigned to it...
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
def mandelbrot(x, y, threshold):
"""Calculates whether the number c = x + i*y belongs to the
Mandelbrot set. In order to belong, the sequence z[i + 1] = z[i]**2 + c
must not diverge after 'threshold' number of steps. The sequence diverges
if the absolute value of z[i+1] is greater than 4.
"""
c = complex(x, y)
z = complex(0, 0)
for i in range(threshold):
z = z**2 + c
if abs(z) > 4.: # it diverged
return i
return threshold - 1 # it didn't diverge
x_start, y_start = -2, -1.5
width, height = 3, 3
density_per_unit = 250
# real and imaginary axis
re = np.linspace(x_start, x_start + width, width * density_per_unit )
im = np.linspace(y_start, y_start + height, height * density_per_unit)
def animate(i):
ax.clear()
ax.set_xticks([], [])
ax.set_yticks([], [])
X = np.empty((len(re), len(im)))
threshold = round(1.15**(i + 1))
# iterations for the current threshold
for i in range(len(re)):
for j in range(len(im)):
X[i, j] = mandelbrot(re[i], im[j], threshold)
# associate colors to the iterations with an iterpolation
img = ax.imshow(X.T, interpolation="bicubic", cmap='magma')
return [img]
fig = plt.figure(figsize=(10, 10))
ax = plt.axes()
anim = FuncAnimation(fig, animate, frames=45, interval=100, repeat=True)

Animate the evolution of a Markov Chain on a 2 dimensional array with python matplotlib imshow

I am trying to write the Metropolis Algorithm for the Hardcore Model on the 2 dimensional lattice. The algorithm I wrote so far seems to work and is as follows:
-Pick a vertex of the 2-d lattice
-Toss a fair coin
-If the coin comes up heads and all neighbors of the vertex take value 0 then set the vertex to 1 otherwise to 0.
I try to animate the evolution of the lattice. Here is what I wrote so far:
The Algorithm to simulate works. The animation not as I want.
Here is the algorithm:
import random
from matplotlib import animation
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
def Nachbarn(x0,x1,B): #test neighbours
if x1 +1 < len(B) and B[x0][x1+1] == 1 : #top
return True
elif x0 + 1 < len(B) and B[x0+1][x1] == 1 : #right
return True
elif x1 -1 >= 0 and B[x0][x1 -1] == 1 : #down
return True
elif x0 -1 >= 0 and B[x0-1][x1] == 1 : #left
return True
else:
return False
def Eckenwahl(B):
Länge = len(B)
x = random.choices(range(Länge),k=2) #choose a vertex
x0 = x[0]
x1 = x[1]
return x0,x1
def Münzwurf():
value = random.randint(0,1) #Toss a coin
return value
def MCMC(Array): #MCMC i-te Iteration
Ecke = Eckenwahl(Array)
if Münzwurf() == 1 and Nachbarn(Ecke[0],Ecke[1],Array) == False:
Array[Ecke[0]][Ecke[1]] = 1
else:
Array[Ecke[0]][Ecke[1]] = 0
return Array
Now, initialize the lattice:
N = 10 #Initialisierung of empty lattice
A = [[0] * N for i in range(N)]
If I apply the function MCMC on the array "A" a few times and start the animation with a non-empty lattice:
for i in range(5):
A = MCMC(A)
the animation seems to run, otherwise its stuck in the empty lattice and does not move forward. But I want to start it with an empty lattice. Here are two solutions that have these constraints so far:
Solution 1:
fig = plt.figure()
im = plt.imshow(A, animated = True)
def update_fig(*args):
global A
B = MCMC(A)
im.set_data(B)
return im
ani = animation.FuncAnimation(fig, update_fig, interval = 1)
plt.show()
Solution 2:
fps = 300
nSeconds = 10
fig = plt.figure( figsize=(8,8) )
a = A
im = plt.imshow(A)
def animate_func(i):
im.set_array(MCMC(A))
return [im]
anim = animation.FuncAnimation(fig, animate_func, frames = nSeconds *
fps,interval = 1000 / fps,)
The issue is, everything is ready. I want to start with a 2-d array/lattice that is full with 0`s called the empty configuration then, at time t=1 apply the function MCMC on the array, next display it in the animation and so on for t=2,3,...
Thanks for the help!

Progressively filter/smooth a signal in python (to straight line on the left to no filtering on the right)

A picture is worth a thousand words (sorry for the shoddy work):
If the solution is preserving the value and the slope at both ends it is better.
If, in addition, the position and sharpness of the transition can be adjusted it is perfect.
But I have not found any solution yet...
Thank you very much for your help
Here is a piece of code to get started:
import matplotlib.pyplot as plt
from scipy.signal import savgol_filter
import numpy as np
def round_up_to_odd(f):
return np.int(np.ceil(f / 2.) * 2 + 1)
def generateRandomSignal(n=1000, seed=None):
"""
Parameters
----------
n : integer, optional
Number of points in the signal. The default is 1000.
Returns
-------
sig : numpy array
"""
np.random.seed(seed)
print("Seed was:", seed)
steps = np.random.choice(a=[-1, 0, 1], size=(n-1))
roughSig = np.concatenate([np.array([0]), steps]).cumsum(0)
sig = savgol_filter(roughSig, round_up_to_odd(n/20), 6)
return sig
n = 1000
t = np.linspace(0,10,n)
seed = np.random.randint(0,high=100000)
#seed = 45136
sig = generateRandomSignal(seed=seed)
###############################
# ????
# sigFilt = adaptiveFilter(sig)
###############################
# Plot
plt.figure()
plt.plot(t, sig, label="Signal")
# plt.plot(t, sigFilt, label="Signal filtered")
plt.legend()
Simple convolution does smoothing. However, as mentioned below, here we need strong smoothing first and no smoothing towards the end. I used the moving average approach with the dynamic size of the window. In the example below, the window size changes linearly.
def dynamic_smoothing(x, start_window_length=(len(x)//2), end_window_length=1):
d_sum = np.cumsum(a, dtype=float)
smoothed = list()
for i in range(len(x)):
# compute window length
a = i / len(x)
w = int(np.round(a * start_window_length + (1.0-a) * end_window_length))
# get the window
w0 = max(0, i - w) # the window must stay inside the array
w1 = min(len(x), i + w)
smoothed.append(sum(x[w0:w1])/(w1+w0))
return np.array(smoothed)

Programming of 4th order Runge-Kutta in advection equation in python

%matplotlib notebook
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from math import pi
# wave speed
c = 1
# spatial domain
xmin = 0
xmax = 1
#time domain
m=500; # num of time steps
tmin=0
T = tmin + np.arange(m+1);
tmax=500
n = 50 # num of grid points
# x grid of n points
X, dx = np.linspace(xmin, xmax, n+1, retstep=True);
X = X[:-1] # remove last point, as u(x=1,t)=u(x=0,t)
# for CFL of 0.1
CFL = 0.3
dt = CFL*dx/c
# initial conditions
def initial_u(x):
return np.sin(2*pi*x)
# each value of the U array contains the solution for all x values at each timestep
U = np.zeros((m+1,n),dtype=float)
U[0] = u = initial_u(X);
def derivatives(t,u,c,dx):
uvals = [] # u values for this time step
for j in range(len(X)):
if j == 0: # left boundary
uvals.append((-c/(2*dx))*(u[j+1]-u[n-1]))
elif j == n-1: # right boundary
uvals.append((-c/(2*dx))*(u[0]-u[j-1]))
else:
uvals.append((-c/(2*dx))*(u[j+1]-u[j-1]))
return np.asarray(uvals)
# solve for 500 time steps
for k in range(m):
t = T[k];
k1 = derivatives(t,u,c,dx)*dt;
k2 = derivatives(t+0.5*dt,u+0.5*k1,c,dx)*dt;
k3 = derivatives(t+0.5*dt,u+0.5*k2,c,dx)*dt;
k4 = derivatives(t+dt,u+k3,c,dx)*dt;
U[k+1] = u = u + (k1+2*k2+2*k3+k4)/6;
# plot solution
plt.style.use('dark_background')
fig = plt.figure()
ax1 = fig.add_subplot(1,1,1)
line, = ax1.plot(X,U[0],color='cyan')
ax1.grid(True)
ax1.set_ylim([-2,2])
ax1.set_xlim([0,1])
def animate(i):
line.set_ydata(U[i])
return line,
I want to program in Python an advection equation which is (∂u/∂t) +c (∂u/∂x) = 0. Time should be discretized with Runge-kutta 4th order. Spatial discretiziation is 2nd order finite difference. When I run my code, I get straight line which transforms into sine wave. But I gave as initial condition sine wave. Why does it start as straight line? And I want to have sine wave moving forward. Do you have any idea on how to get sine wave moving forward? I appreciate your help. Thanks in advance!
While superficially your computation steps are related to the RK4 method, they deviate from the RK4 method and the correct space discretization too much to mention it all.
The traditional way to apply ODE integration methods is to have a function derivatives(t, state, params) and then apply that to compute the Euler step or the RK4 step. In your case it would be
def derivatives(t,u,c,dx):
du = np.zeros(len(u));
p = c/(2*dx);
du[0] = p*(u[1]-u[-1]);
du[1:-1] = p*(u[2:]-u[:-2]);
du[-1] = p*(u[0]-u[-2]);
return du;
Then you can do
X, dx = np.linspace(xmin, xmax, n+1, retstep=True);
X = X[:-1] # remove last point, as u(x=1,t)=u(x=0,t)
m=500; # number of time steps
T = tmin + np.arange(m+1);
U = np.zeros((m+1,n),dtype=float)
U[0] = u = initial_u(X);
for k in range(m):
t = T[k];
k1 = derivatives(t,u,c,dx)*dt;
k2 = derivatives(t+0.5*dt,u+0.5*k1,c,dx)*dt;
k3 = derivatives(t+0.5*dt,u+0.5*k2,c,dx)*dt;
k4 = derivatives(t+dt,u+k3,c,dx)*dt;
U[k+1] = u = u + (k1+2*k2+2*k3+k4)/6;
This uses dt as computed as the primary variable in the time stepping, then constructs the arithmetic sequence from tmin with step dt. Other ways are possible, but one has to make tmax and the number of time steps compatible.
The computation up to this point should now be successful and can be used in the animation. In my understanding, you do not produce a new plot in each frame, you only draw the graph once and after that just change the line data
# animate the time data
line, = ax1.plot(X,U[0],color='cyan')
ax1.grid(True)
ax1.set_ylim([-2,2])
ax1.set_xlim([0,1])
def animate(i):
line.set_ydata(U[i])
return line,
etc.

Python Solving 1D wave equation and animating

I adapted a code for solving 1d wave equation. My problem is animating the time dependent results. I tried it with the following code, any idea what I made wrong? I used the animation package, but somehiw it always says that more than one element is ambigous...
from __future__ import division
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import rc
import matplotlib.animation as animation
#Set Helvetica Font
rc('font',**{'family':'sans-serif','sans-serif':['Helvetica']})
## for Palatino and other serif fonts use:
#rc('font',**{'family':'serif','serif':['Palatino']})
rc('text', usetex=True)
class wave1d(object):
def __init__(self,width,T,nx,nt,c):
self.x = np.linspace(-0.5*width,0.5*width,nx)
self.t = np.linspace(0,T,nt+1)
self.dx = self.x[1]-self.x[0]
self.dt = self.t[1]-self.t[0]
self.xx = self.x
# Gamma_x squared
self.gx2 = c*self.dt/self.dx
# 2*(1-gamma_x^2-gamma_y^2)
self.gamma = 2*(1 - self.gx2)
def solve(self,ffun,gfun):
f = ffun(self.xx)
g = gfun(self.xx)
u = np.zeros((nx,nt+1))
# Set initial condition
u[:,0] = f
""" Compute first time step """
u[:,1] = 0.5*self.gamma*f+self.dt*g
u[1:-1,1] += 0.5*self.gx2*(f[2:]+f[:-2])
for k in range(1,nt):
# Every point contains these terms
u[:,k+1] = self.gamma*u[:,k] - u[:,k-1]
# Interior points
u[1:-1,k+1] += self.gx2*(u[2:,k]+u[:-2,k])
# Right boundary
u[-1,k+1] += 2*self.gx2*u[-2,k]
# Left boundary
u[0,k+1] += 2*self.gx2*u[1,k]
return u
if __name__ == '__main__':
# Final time
T = 2
# Domain dimensions
width = 8
# Wave speed
c = 1
# Number of time steps
nt = 400
# Grid points in x direction
nx = 500
wave_eq = wave1d(width,T,nx,nt,c)
# Initial value functions
f = lambda x: np.sin(x-width)
g = lambda x: 0
u = wave_eq.solve(f,g)
x = wave_eq.x
frames = []
fig = plt.figure(1,(16,8))
for k in range(nt+1):
frame = plt.show(u[:,k])
frames.append([frame])
ani = animation.ArtistAnimation(fig,frames,interval=50, blit=True,repeat_delay=1000)
# ani.save('wave1d.mp4',dpi=300)
plt.show()

Categories