A cellular automata code to simulate the spread of an epidemic - python

I'm only beggining at python so sorry if my question seems simple. I want to simulate the spread of an epidemic using cellular autamata. Here's my code :
import matplotlib.colors
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import colors
from matplotlib.animation import FuncAnimation
import matplotlib.animation as ani
import random as rd
import copy
from matplotlib.colors import ListedColormap
def init_graph():
plt.hlines(y=np.arange(n)+0.5, xmin=-0.5, xmax=n-0.5, linewidth=0.25, color="grey")
plt.vlines(x=np.arange(n)+0.5, ymin=-0.5, ymax=n-0.5, linewidth=0.25, color="grey")
def init_matrix_array(n):
m = np.ones((n, n))
m[n//2][n//2]=2
return m.tolist()
def next_to_ill_cell(current_state_matrix, i, j):
for x in [i-1,i,i+1]:
for y in [j-1,j,j+1]:
if not((x==i and y==j) or x==-1 or y==-1 or x==n or y==n):
if current_state_matrix[x][y]==ill:
return True
return False
#Rules
def process_next_state (current_state_matrix):
previous_state_matrix = copy.deepcopy(current_state_matrix)
for i in range (n) :
for j in range (n) :
if previous_state_matrix[i][j] == untouched:
if next_to_ill_cell(previous_state_matrix, i, j)== True:
k = rd.random()#random
if k >= 0.5:
current_state_matrix[i][j] = ill
else:
current_state_matrix[i][j] = untouched
if previous_state_matrix[i][j]==ill:
s = rd.random()
if s >= 0.02875:
current_state_matrix[i][j] = recovered
else:
current_state_matrix[i][j] = dead
return current_state_matrix
def number_of_death(current_state_matrix):
n_death = 0
for i in range(n):
for j in range(n):
if current_state_matrix[i][j] == dead:
n_death += 1
return n_death
def number_of_recovery(previous_state_matrix, current_state_matrix):
"""Calculate the number of recovery"""
if __name__ == '__main__':
cmap = ListedColormap(['k','w','r','b'])
dead = 0
untouched = 1
ill = 2
recovered = 3
n = 50 #number of array (table of 50*50 : 2500 cells)
init_graph()
current_state_matrix = init_matrix_array(n)
day = 1
while day < 10:
previous_state_matrix = current_state_matrix
# Number of death
n_death = number_of_death(current_state_matrix)
plt.imshow(current_state_matrix, cmap=cmap, vmin=0, vmax=3)
plt.text(25, 5, f'day = {day}', horizontalalignment='center')
plt.text(25, 45, f'number of death = {n_death}', horizontalalignment='center')
current_state_matrix = process_next_state(current_state_matrix)
day += 1
plt.pause(1)
plt.show()
I guess it could be greatly improved but as I said I am a beginner.
I want an infected cell to stay infected for between 4 and 8 days. How should I do that ?

A solution would be to use probabilistic rules where, for example:
Each cell has either a counter of how many days it has been infected or some kind of timestamp to compare to the current CA step.
An infected cell starts with 100% chance of remaining infected on the next day and that probability remains as 100% until 4 days have elapsed.
Starting on the fifth day, reduce that probability by some amount. Repeat this every following day that the cell is still infected.
If it is still infected on the eighth day, make the probability of it remaining infected zero.

Related

For loop with while statement sticking on certain iterations

I have code which simulates a Markov jump process.
I am trying to increase the number of realisations, Rr whilst reducing the computation time. The code is runs for some values and then will randomly get stuck and I don't know why exactly. I think it may be to do with my while loop, although I am unsure on how to get around this. If anyone could provide some insight that would be great.
import numpy as np
import random
import matplotlib.pyplot as plt
import csv
import time
t = time.time()
#Initial jump value
n0 = 1
#Constant
cbar = 1
#Constant
L = 1
#Constant
tau = 2*L/cbar
#Empty list to store N series
N_array = []
#Empty list to store z series
z_array = []
#Number of initial realisations
Rr = 2000
for r in range(0,Rr):
#Set initial z series values to be zero
z = [0]
#Set initial jump process values to be n0
N = [n0]
#Set iteration to be zero
j = 0
#While the value of N[j] series (realisation r) is greater than zero and j is less than jmax
while N[j] > 0:
#Form next value in z series according to exponential clock, parameter n^2, since Lloc = 2, cbar = 1, L=1
#In python the argument of this function is beta = 1/lambda, hence 1/n^2
z.append(z[j] + np.random.exponential(1/N[j]**2))
#Pick jump at position j+1 to be N[j] -1 or +1 with prob 1/2
N.append(N[j] + np.random.choice([-1,1]))
#Update iteration
j = j+1
#Store N,z realisation if sum dz < 10 say
if sum(np.diff(z)) < 10:
N_array.append(N)
z_array.append(z)
print(r/RR*100,'%)
elapsed = time.time() - t
print('Elapsed time =',elapsed,'seconds')

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!

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.

Output multiple plots in Python for animation

Im trying to animate a non-dispersive wave packet. My idea is to output the wave function at many different time points and then add individuals photos to make an animation. My Python code kind of the job but it repeats the previous plots in all following plots and i dont know how to fix it.
import matplotlib.pyplot as plt
import numpy as np
k = np.linspace(1,100,1000)
#x = np.linspace(-n<p.pi,np.pi,100)
x = np.linspace(0,70,71)
fac = np.linspace(0,1,1000)
result = []
n = 800
t = np.linspace(-150,150,n)
vp = -1
E0 = 1
w0 = 1
T = 10
def wave(k,x):
return abs(np.sin(x-k))
def packet(E0,t,w0,T,x):
return E0*np.cos(w0*(t+vp*x))*np.exp(-(t+vp*x)**2/T**2)
j = len(fac)-1
#while j >= 0:
#for i in range(len(k)):
# result.append(wave(k[i],x))
#j -= 1
b = np.array(result)
c = np.sum(b,axis = 0)
#plt.plot(x,c)
#plt.show()
counter = 0
i=0
while counter <= 71:
plt.plot(t,packet(E0,t,w0,T,i),label = 't = %d' %(i))
plt.savefig("time%d.pdf" %i)
i += 1
counter += 1
You can rewrite your cycle like this:
while counter <= 71:
plt.cla() # clean current axis
plt.plot(t, packet(E0,t,w0,T,i),label = 't = %d' %(i))
plt.ylim([-1.1, 1.1]) # establish limits for better visualization
plt.savefig("time%d.jpg" %i)
i += 1
counter += 1
also you can create animation according this example

The Birthday paradox - how to plot

from __future__ import division, print_function
from numpy.random import randint
import random
import numpy as np
%matplotlib inline
import matplotlib.pyplot as plt
def bday(c):
trials = 5000
count = 0
for trial in range(trials):
year = [0]*365
l = False
for i in range(c):
bdayp = randint(1,365)
year[bdayp] = year[bdayp] + 1
if year[bdayp] > 1:
l = True
if l == True:
count = count + 1
prob = count / trials
return prob
for i in range(2,41):
a = bday(i)
print(i,a)
As you can see, I generate the number of people in the class along with the probability that they share a birthday. How can I plot this so that I have n (number of people) on the x-axis and probability on the y-axis using matplotlib.pyplot?
Thanks.
I've linked in the comments the proper documentation to your problem. For the sake of you finding your own solution, perhaps looking at the following might make more sense of how to go about your problem:
def func(x):
return x * 10
x = []
y = []
for i in range(10):
x.append(i)
y.append(func(i))
plt.plot(x, y)
The above can also be achieved by doing the following:
def func(x):
return x * 10
x = np.arange(10)
plt.plot(x, func(x))
Here is the documentation for np.arange; both will plot the following:

Categories