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)
Related
I create a pcolormesh for the 2D diffusion equation creating a 3D array of x, y and t. A static 2D plot for a specific t is straightforward. How can I animate it over all the time steps?
I create my 3D array using the following:
set array for x and y
grid_size = 100
t_iter = 1000
D = .01
length = 1.0
tmax = 1.0
dx = dy = length/grid_size
dt = tmax/t_iter
rho = np.zeros((grid_size, grid_size, t_iter))
#rho[:] = 1.2
rho[grid_size//2, grid_size//2, 0] = 1.2 # set the initial configuration
for n in range(t_iter-1):
for j in range(grid_size-1):
for i in range(grid_size-1):
pxx = rho[i+1,j,n] + rho[i-1,j,n] - 2*rho[i,j,n]
pyy = rho[i,j+1,n] + rho[i,j-1,n] - 2*rho[i,j,n]
rho[i,j,n+1] = D*dt*(pxx/dx**2+pyy/dy**2)
I can plot the data using pcolormesh (without the labels and stuff) for specific values of t:
plt.pcolormesh(rho[:,:,500])
I tried this, but it doesn't "animate" anything. What am I missing?
from matplotlib.animation import FuncAnimation
fig, ax = plt.subplots()
mesh = ax.pcolormesh(rho[:,:,0])
def animate(i):
ax.pcolormesh(rho[:,:,i])
anim = FuncAnimation(fig, animate, interval=10, frames=t_iter-1, repeat=False)
plt.draw()
plt.show()
Three things are going wrong:
In animate(), the mesh should be updated. mesh.set_array() sets new values. As the internal data structure needs a 1D array, the 2D array should be "raveled": mesh.set_array(rho[:, :, i].ravel()).
animate() should return a list of the changed elements. The trailing comma in return mesh, is Python's way to make a "tuple" of just one element.
The most tricky problem here, is that preferably all images use the same color mapping. vmin tells which value maps to the "lowest" color (dark purple in the default viridis map), while vmax corresponds to the value for the "highest" color (yellow in viridis). If they are net set explicitly, matplotlib will calculate them as the minimum and maximum of the first image, 0 and 1.2 in this case. These values don't go well for the other images. Usually, the overall minimum and maximum give suitable values. But, in this case, the "interesting" part of the image is in a much narrower range. I experimented using the 1st and 99th percentiles, which seem to work well, but you'll probably want to adapt these values.
The updated code:
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
import numpy as np
grid_size = 100
t_iter = 1000
D = .01
length = 1.0
tmax = 1.0
dx = dy = length / grid_size
dt = tmax / t_iter
rho = np.zeros((grid_size, grid_size, t_iter))
# rho[:] = 1.2
rho[grid_size // 2, grid_size // 2, 0] = 1.2 # set the initial configuration
for n in range(t_iter - 1):
for j in range(grid_size - 1):
for i in range(grid_size - 1):
pxx = rho[i + 1, j, n] + rho[i - 1, j, n] - 2 * rho[i, j, n]
pyy = rho[i, j + 1, n] + rho[i, j - 1, n] - 2 * rho[i, j, n]
rho[i, j, n + 1] = D * dt * (pxx / dx ** 2 + pyy / dy ** 2)
fig, ax = plt.subplots()
mesh = ax.pcolormesh(rho[:, :, 0], vmin=np.percentile(rho.ravel(), 1), vmax=np.percentile(rho.ravel(), 99))
def animate(i):
mesh.set_array(rho[:, :, i].ravel())
return mesh,
anim = FuncAnimation(fig, animate, interval=10, frames=t_iter, repeat=False)
plt.show()
I want to implement the fourier transform of a periodic function, e.g. exp(iwt). Here is an example of how I implemented it.
max_f = 100
dt = 0.002
# discretized frequency
farray = np.linspace(0, max_f, 101).astype(np.float128)
# fourier transform kernel
ft_kernel = np.exp(-1.j * 2. * (np.pi) * farray * dt)
# storage of fourier transform until current time step, for graphing purpose
store = np.zeros([1000, 101], dtype=np.complex128)
# The actual fourier transform calculated until current time step
current = np.zeros([101], dtype=np.complex128)
for i in range(10000):
for fre in range(101):
current[fre] = current[fre] + (ft_kernel[fre]**i) * np.exp(np.complex(1j * 2. * np.pi * 50.0 * dt * int(i)));
# store it every 10 step to plot the convergence graph
if i % 10 == 0:
store[i // 10] = current
# calculate the psd
result = np.abs(store * dt)**2
Code for generating video:
from IPython.display import HTML
total_steps = 300
fig, ax = plt.subplots(1, 1, figsize=(10, 5))
ax.set_ylim(-15, 15)
ax.set_xlim(0, 100)
ln, = ax.plot([], [], 'b-')
ax.set_xlabel('frequency')
ax.set_ylabel('db')
title = ax.text(0.5,0.85, "", bbox={'facecolor':'w', 'alpha':0.5, 'pad':5},
transform=ax.transAxes, ha="center")
plt.close()
def animate_func(i):
if i % 100 == 0:
print(i , end ='')
ln.set_data(np.linspace(0, 100, 101), np.log(result[i]))
ax.set_title(f'{i * 10} of {300 * 10}')
return ln,
anim = FuncAnimation(fig, animate_func, frames = total_steps, interval=50, blit=False)
HTML(anim.to_html5_video())
Formula I'm using:
where the blue f(t) is the periodic function's value and in this case exp(iwt).
However, when I plot the convergence out, it always have the behavior of first converge then diverge and repeats...
I can't find the reason, is it possible to seek some help here?
Here is the gif:
Thanks in advance!
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.
With some help I have produced the following code. Below are some of the desired outputs for given inputs. However I am having some trouble completing the last task of this code. Looking for some help with this, any guidance or help is greatly appreciated, thanks!
flops = 0
def add(x1, x2):
global flops
flops += 1
return x1 + x2
def multiply(x1, x2):
global flops
flops += 1
return x1 * x2
def poly_horner(A, x):
global flops
flops = 0
p = A[-1]
i = len(A) - 2
while i >= 0:
p = add(multiply(p, x), A[i])
i -= 1
return p
def poly_naive(A, x):
global flops
p = 0
flops = 0
for i, a in enumerate(A):
xp = 1
for _ in range(i):
xp = multiply(xp, x)
p = add(p, multiply(xp, a))
return p
Given the following inputs, I got the following outputs:
poly_horner([1,2,3,4,5], 2)
129
print(flops)
8
poly_naive([1,2,3,4,5, 2])
129
print(flops)[![enter image description here][1]][1]
20
np.polyval([5,4,3,2,1], 2)
129
I assume you want to create a figure, though your question is quite vague...but I have a few minutes to kill while my code runs. Anyway, it seems you MIGHT be having difficulty plotting.
import numpy as np
import pylab as pl
x = np.arange(10)
y = x * np.pi
# you can calculate a line of best fit (lobf) using numpy's polyfit function
lobf1 = np.polyfit(x, y, 1) # first degree polynomial
lobf2 = np.polyfit(x, y, 2) # second degree polynomial
lobf3 = np.polyfit(x, y, 3) # third degree polynomial
# you can now use the lines of best fit to calculate the
# value anywhere within the domain using numpy's polyval function
# FIRST, create a figure and a plotting axis within the fig
fig = pl.figure(figsize=(3.25, 2.5))
ax0 = fig.add_subplot(111)
# now use polyval to calculate your y-values at every x
x = np.arange(0, 20, 0.1)
ax0.plot(x, np.polyval(lobf1, x), 'k')
ax0.plot(x, np.polyval(lobf2, x), 'b')
ax0.plot(x, np.polyval(lobf3, x), 'r')
# add a legend for niceness
ax0.legend(('Degree 1', 'Degree 2', 'Degree 3'), fontsize=8, loc=2)
# you can label the axes whatever you like
ax0.set_ylabel('My y-label', fontsize=8)
ax0.set_xlabel('My x-label', fontsize=8)
# you can show the figure on your screen
fig.show()
# and you can save the figure to your computer in different formats
# specifying bbox_inches='tight' helps eliminate unnecessary whitespace around
# the axis when saving...it just looks better this way.
pl.savefig('figName.png', dpi=500, bbox_inches='tight')
pl.savefig('figName.pdf', bbox_inches='tight')
# don't forget to close the figure
pl.close('all')
I'm trying to do some animation with matplotlib (Conways game of life, to be specific) and have some problems with the .FuncAnimation
I figured out diffrent cases wich partly worked (but not the way I want) or result in diffrent errors. I would like to understand the errors and work out a proper version of the code. Thanks for your help!
The function called through the .FuncAnimation is gameoflife wich uses the variables w, h, grid to uptdate the image.
For the whole commented code see below.
Case 1: Global Variables
If I use global variables everthing works fine.
I define w, h, grid global before i call gameoflife(self) through anim = animation.FuncAnimation(fig, gameoflife)
In gameoflife(self) i also define w, h, grid as global variables
w, h, grid = "something"
def gameoflife(self):
global w
global h
global grid
.
.
.
img = ax.imshow(grid)
return img
fig, ax = plt.subplots()
plt.axis('off')
img = ax.imshow(grid)
anim = animation.FuncAnimation(fig, gameoflife)
plt.show()
As said, this results in the animation as wanted. But I would like to get rid of the global variables, because of which I tried something else:
Case 2: Passing Objects
I don't defined w, h, grid as globals in gameoflife but passed them with anim = animation.FuncAniation(fig, gameoflife(w,h,grid)).
(I know that w, h, grid are still global in my example. I work on another version where they are not but since the errors are the same I think this simplyfied version should do it.)
This results in the following Error:
TypeError: 'AxesImage' object is not callable
I dont understand this error, since I don't call ax with the code changes.
w, h, grid = "something"
def gameoflife(w, h, grid):
.
.
.
img = ax.imshow(grid)
return img
fig, ax = plt.subplots()
plt.axis('off')
img = ax.imshow(grid)
anim = animation.FuncAnimation(fig, gameoflife(w,h,grid))
plt.show()
Case 3: Passing Objects with fargs
In the third case I try to pass w, h, grid with the "frags" argument of .FuncAnimation resulting in just the first frame. (Or the first two, depending how you see it. The "frist" frame is accually drawn through img = ax.imshow(grid))
w, h, grid = "something"
def gameoflife(self, w, h, grid):
.
.
.
img = ax.imshow(grid)
return img
fig, ax = plt.subplots()
plt.axis('off')
img = ax.imshow(grid)
anim = animation.FuncAnimation(fig, gameoflife, fargs=(w,h,grid))
plt.show()
Complete Code
I hope its properly commented ;)
There are two parts (beginning and end) where you can comment/uncomment parts to generate the respective case. By deafault its Case 1.
import random
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
##defining grid size
w= 20
h = 20
##generating random grid
grid = np.array([[random.randint(0,1) for x in range(w)] for y in range(h)])
######
# Choose for diffrent cases
######
##Case 1: Global Variables
def gameoflife(self):
global w
global h
global grid
##Case 2: Passing Objects
#def gameoflife(w, h, grid):
##Case 3: Passing Objects with fargs
#def gameoflife(self, w, h, grid):
####### Choose part over
# wt, ht as test values for position
# x,y to set calculation position
wt = w-1
ht = h-1
x,y = -1,0 #results in 0,0 for the first postion
# defining grid for calculation (calgrid)
calgrid = np.array([[0 for x in range(w)] for y in range(h)])
# testing for last position
while y<ht or x<wt:
# moving position through the grid
if x == wt:
y +=1
x = 0
else:
x += 1
#sorrounding cells check value
scv = 0
#counting living cells around position x,y
#if-else for exeptions at last column and row
if y == ht:
if x == wt:
scv = grid[x-1][y-1] + grid[x][y-1] + grid[0][y-1] + grid[x-1][y] + grid[0][y] + grid[x-1][0] + grid[x][0] + grid[0][0]
else:
scv = grid[x-1][y-1] + grid[x][y-1] + grid[x+1][y-1] + grid[x-1][y] + grid[x+1][y] + grid[x-1][0] + grid[x][0] + grid[x+1][0]
else:
if x == wt:
scv = grid[x-1][y-1] + grid[x][y-1] + grid[0][y-1] + grid[x-1][y] + grid[0][y] + grid[x-1][y+1] + grid[x][y+1] + grid[0][y+1]
else:
scv = grid[x-1][y-1] + grid[x][y-1] + grid[x+1][y-1] + grid[x-1][y] + grid[x+1][y] + grid[x-1][y+1] + grid[x][y+1] + grid[x+1][y+1]
# test cell to condidions and write result in calgrid
if grid[x][y] == 0:
if scv == 3:
calgrid [x][y] = 1
else :
if 1<scv<4:
calgrid [x][y] = 1
# updating grid, generating img and return it
grid = calgrid
img = ax.imshow(grid)
return img
fig, ax = plt.subplots()
plt.axis('off')
img = ax.imshow(grid) #generates "first" Frame from seed
#####
# Choose vor Case
#####
## Case 1: Global Variables
anim = animation.FuncAnimation(fig, gameoflife)
## Case 2: Passing Variables
#anim = anim = animation.FuncAnimation(fig, gameoflife(w,h,grid))
## Case 3: Passing Variables with fargs
#anim = animation.FuncAnimation(fig, gameoflife, fargs=(w,h,grid))
####### Choose part over
plt.show()
Tanks for help and everything
Greetings Tobias
Case 2: You call the function and pass the result into FuncAnimation.
def gameoflife(w,h,grid):
# ...
return ax.imshow(grid)
anim = animation.FuncAnimation(fig, gameoflife(w,h,grid))
Is essentially the same as
anim = animation.FuncAnimation(fig, ax.imshow(grid))
which will not work because the second argument is expected to be a function, not the return of a function (in this case an image).
To explain this better, consider a simple test case. g is a function and expects a function as input. It will return the function evaluated at 4. If you supply a function f, all works as expected, but if you supply the return of a function, it would fail if the return is not itself a function, which can be evaluated.
def f(x):
return 3*x
def g(func):
return func(4)
g(f) # works as expected
g(f(2)) # throws TypeError: 'int' object is not callable
Case 3: You calling the function repeatedly with the same arguments
In the case of
anim = animation.FuncAnimation(fig, gameoflife, fargs=(w,h,grid))
you call the function gameoflife with the same initial arguments w,h,grid for each frame in the animation. Hence you get a static animation (the plot is animated, but each frame is the same, because the same arguments are used).
Conclusion. Stay with Case 1
Because case 1 is working fine, I don't know why not use it. A more elegant way would be to use a class and use class variables as e.g. in this question.