Is there a way to iteratively add plots to Animation.FuncAnimation()? - python

I'm working on my master thesis right now and need to animate a high number of points moving. Those points will be representing predators and prey. The number of predators and preys should be changeable and probably around 500 each. For now i hard coded the animation function with 3 predators and 1 prey. is there a way to do it iteratively (e.g for 500 predators and 200 preys)?
EDIT: In google colab the animation is stretched is there a way to make it a proper square?
Thanks in advance!
My code so far (just have random movement for p&p so code is smaller):
import matplotlib
import random
import numpy as np
from matplotlib import pyplot
from matplotlib import animation
from matplotlib import rc
rc('animation', html='jshtml')
max_t=200 # max experiment time
num_pred = 3 # number of predators
num_prey = 1 # number of prey
pred_pos = np.zeros((2*num_pred, max_t)) # initializing x and y positions for pred based on time
prey_pos = np.zeros((2*num_prey, max_t)) # initializing x and y positions for prey based on time
# [pred1_x1, pred1_x2, pred1_x3,...
# pred1_y1, pred1_y2, pred1_y3,...
# pred2_x1, pred2_x2, pred2_x3,...
# pred2_y1, pred2_y2, pred2_y3,...]
for i in range(2*num_pred):
pred_pos[i][0] = pred_pos[i][0] + random.uniform(-1, 1)
for j in range(max_t-1):
pred_pos[i][j] = pred_pos[i][j-1] + random.uniform(-1, 1) # random movement
for i in range(2*num_prey):
prey_pos[i][0] = prey_pos[i][0] + random.uniform(-1, 1)
for j in range(max_t-1):
prey_pos[i][j] = prey_pos[i][j-1] + random.uniform(-1, 1)
#print(pred_pos)
#print(prey_pos)
fig=pyplot.figure()
ax = pyplot.axes(xlim=(-10, 10), ylim=(-10, 10))
pred_circle1=pyplot.Circle((pred_pos[0,0],pred_pos[1,0]),0.3,fc='b')
pred_circle2=pyplot.Circle((pred_pos[2,0],pred_pos[3,0]),0.3,fc='b')
pred_circle3=pyplot.Circle((pred_pos[4,0],pred_pos[5,0]),0.3,fc='b')
prey_circle1=pyplot.Circle((prey_pos[0,0],prey_pos[1,0]),0.3,fc='r')
def init():
pred_circle1.center=(pred_pos[0,0],pred_pos[1,0]) # pred_circle1.center=(x,y)
pred_circle2.center=(pred_pos[2,0],pred_pos[3,0])
pred_circle3.center=(pred_pos[4,0],pred_pos[5,0])
prey_circle1.center=(prey_pos[0,0],prey_pos[1,0])
ax.add_patch(pred_circle1)
ax.add_patch(pred_circle2)
ax.add_patch(pred_circle3)
ax.add_patch(prey_circle1)
return pred_circle1, pred_circle2, pred_circle3, prey_circle1,
def animate(i):
pred_circle1.center=(pred_pos[0,i],pred_pos[1,i])
pred_circle2.center=(pred_pos[2,i],pred_pos[3,i])
pred_circle3.center=(pred_pos[4,i],pred_pos[5,i])
prey_circle1.center=(prey_pos[0,i],prey_pos[1,i])
return pred_circle1, pred_circle2, pred_circle3, prey_circle1,
anim=animation.FuncAnimation(fig,animate, init_func=init,frames=max_t,blit=True)
anim

One way to achieve it is by knowing that your first add all the predators, then all the preys. So, ax.patches contains an ordered list of patches, and you can loop over them to update their positions:
import matplotlib
import random
import numpy as np
from matplotlib import pyplot
from matplotlib import animation
max_t=200 # max experiment time
num_pred = 15 # number of predators
num_prey = 4 # number of prey
pred_pos = np.zeros((2*num_pred, max_t)) # initializing x and y positions for pred based on time
prey_pos = np.zeros((2*num_prey, max_t)) # initializing x and y positions for prey based on time
# [pred1_x1, pred1_x2, pred1_x3,...
# pred1_y1, pred1_y2, pred1_y3,...
# pred2_x1, pred2_x2, pred2_x3,...
# pred2_y1, pred2_y2, pred2_y3,...]
for i in range(2*num_pred):
pred_pos[i][0] = pred_pos[i][0] + random.uniform(-1, 1)
for j in range(max_t-1):
pred_pos[i][j] = pred_pos[i][j-1] + random.uniform(-1, 1) # random movement
for i in range(2*num_prey):
prey_pos[i][0] = prey_pos[i][0] + random.uniform(-1, 1)
for j in range(max_t-1):
prey_pos[i][j] = prey_pos[i][j-1] + random.uniform(-1, 1)
fig=pyplot.figure()
ax = pyplot.axes(xlim=(-10, 10), ylim=(-10, 10))
# add an arbitrary number of preys and predators
for i in range(num_pred):
p = pyplot.Circle((pred_pos[2 * i, 0], pred_pos[2 * i + 1, 0]),0.3,fc='b')
ax.add_patch(p)
for i in range(num_prey):
p = pyplot.Circle((prey_pos[2 * i, 0], prey_pos[2 * i + 1, 0]),0.3,fc='r')
ax.add_patch(p)
def animate(i):
# update positions
for k in range(num_pred):
ax.patches[k].center=(pred_pos[2*k,i],pred_pos[2*k+1,i])
for k in range(num_prey):
ax.patches[num_pred + k].center=(prey_pos[2*k,i],prey_pos[2*k+1,i])
anim=animation.FuncAnimation(fig,animate, frames=max_t)
pyplot.show()

Related

Matrix animation

I have a matrix, that represents the evolution of the Temperature of a zone, depending on the position and the time. Each row refers to each instant, and each column refers to each position.
I want to create an animation that plots, gradually, all the rows of the matrix one by one, so I can visualise more graphycally the evolution of the temperature from every position at the same time, while time evolves.
I tried to create a for loop inside of the animation function, but it didin't work at all. It has to work through a loop, as the matrix's size is 100x1000.
This is the code I have:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
N = 100
T = np.zeros((1000, N))
dz = 1/N
dt = 0.25*dz**2
T_0 = 43351/94400
for j in range(N):
T[0][j] = T_0
for i in range(999):
T[i+1][0] = T_0
T[i+1][N-1] = T_0
for i in range(999):
for j in range(1, 99):
T[i+1][j] = (dt/dz**2)*(T[i][j+1] - 2*T[i][j] + T[i][j-1]) + dt + T[i][j]
x = []
for i in range(100):
x.append(i*dz)
Every row of the matrix should be plotted as the y axis, and the x axis should be this 'x' list I made at the end.

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)

Simulating the trajectory of a particle from rest under gravity

I hope you can help! I need to show the trajectory of a particle that is under gravity of g = -9.81 m/s2 and time step of dt = 0.05 sec, where the position and velocity of the particle are:
x_1 = x_0 + v_x1 * dt
y_1 = y_0 + v_y1 * dt
v_x1 = v_x0
v_y1 = v_y0 + g * dt
This is what I should achieve:
This is what I've done so far:
import numpy as np
import matplotlib.pyplot as plt
plt.figure(1, figsize=(12,12))
ax = plt.subplot(111, aspect='equal')
ax.set_ylim(0,50)
ax.set_title('Boom --- Weeee! --- Ooof')
r = np.array([0.,0.,15.,30.])
g = -9.81
dt = 0.05
y = 0
x = 0
while y > 0:
plt.plot(x_1,y_2,':', ms=2)
x_1 = v_x1 * dt
y_1 = v_y1 * dt
v_x1 = v_x0
v_y1 = v_y0 + g * dt
This doesn't produce an image only the plt.figure stated in the beginning, I've tried to integrate the r vector into the loop but I can't figure out how.
Thank you.
Here's a modified version of your code that I believe gives you the result you desire (you may want to choose different initial velocity values):
import matplotlib.pyplot as plt
# Set up our plot surface
plt.figure(1, figsize=(12,12))
ax = plt.subplot()
# ax = plt.subplot(111, aspect='equal')
# ax.set_ylim(0,50)
ax.set_title('Boom --- Weeee! --- Ooof')
# Initial conditions
g = -9.81
dt = 0.05
y = 0
x = 0
v_x = 5
v_y = 5
# Create our lists that will store our data points
points_x = []
points_y = []
while True:
# Add the current position of our projectile to our data
points_x.append(x)
points_y.append(y)
# Move our projectile along
x += v_x * dt
y += v_y * dt
# If our projectile falls below the X axis (y < 0), end the simulation
if y < 0:
break
# Update our y velocity per gravity
v_y = v_y + g * dt
# Plot our data
ax.plot(points_x, points_y)
# Show the plot on the screen
plt.show()
I'm sorry if I could have made fewer changes. Here are the substantive ones I can think of:
You weren't using the r value you computed, so got rid of it, along with the import of numpy that was then no longer needed.
I took out calls you made explicitly size your plot. You're better off letting the plot library decide upon the bounds of the plot for you
I don't know if there's another way to do it, but I've always supplied data to the plotting library as arrays of points rather than by providing the points one at a time. So here, I collect up all of the x and y coordinates into two lists while running the simulation, and then add those arrays to the plot at the end to plot the data.
The x_0 vs x_1, etc., got confusing for me. I didn't see any reason to keep track of multiple position and velocity values, so I reduced the code down to using just one set of positions and velocities, x, y, v_x and v_y.
See the comments for more info
Result:

Matplotlib FuncAnimation not displaying any frames until animation is complete

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.

efficient discrete bayes filter for localization

I'm trying to implement a discrete bayes filter (i.e. histogram filter) for robot localization as described in 'Probabilistic Robotics' by Thrun, Burgard, and Fox. The model is a robot that moves in one dimensions, so the state vector is just the position and velocity. At each time step there is a random acceleration with mean of zero and variance of one.
I think that my implementation is accurate, but it runs slowly. I'm looping over indices of my probability density map which seems very inefficient, but I don't see how to vectorize this algorithm correctly. Any suggestions?
My code:
import matplotlib.pyplot as plt
import numpy as np
from math import pi, exp, sqrt
import matplotlib.cm as cm
N = 31
numsteps = 5
# set up grid
x = np.linspace(-10, 10, N)
v = np.linspace(-10, 10, N)
sp = (x[1] - x[0])/2
X, V = np.meshgrid(x, v)
# initial probability distribution is a delta function at origin
p0 = np.zeros(X.shape)
p0[N/2, N/2] = 1
plt.ion()
plt.imshow(p0, cmap = cm.Greys_r, interpolation='none')
plt.draw()
acc_var = 1 # Variance of random acceleration
for ii in range(numsteps):
print 'Step %d'%ii
p1 = np.zeros(X.shape)
for (i, j), p in np.ndenumerate(p0): #outer loop over configuration space
for (k,l), x in np.ndenumerate(X):
# new position is old position plus velocity
if X[i,j] > X[k,l] + V[k,l] - sp and X[i,j] <= X[k,l] + V[k,l] + sp:
# Bayesian update with random acceleration
p1[i,j] = p1[i,j] + exp(-0.5 * (V[i,j] - V[k,l])**2 / acc_var) / sqrt(2*pi*acc_var) * p0[k,l]
p0 = p1
plt.imshow(p1, cmap = cm.Greys_r, interpolation='none')
plt.draw()

Categories