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
Related
I am trying to plot a matrix in Python. So, my initial thought was using matshow.
However, this particular matrix develop over time via an algorithm (the function sandpile below), so I need to show how the matrix develop over time - but in the same plot. The end result is sort of an animation. Any ideas as to how that is done ? The code below only produce one graph, and that is a picture of the very last updated matrix (matrix called abba, below).
Thank you in advance.
import numpy as np
import matplotlib.pyplot as plt
dimension = 3
abba = np.matrix( [ [2,5,2], [1,1000,4], [2,1,2] ] )
def sandpile(field):
greater3 = np.where(field > 3)
left = (greater3[0], greater3[1]-1)
right = (greater3[0], greater3[1]+1)
top = (greater3[0] - 1, greater3[1])
bottom = (greater3[0]+1 , greater3[1])
bleft = left[0][np.where(left[1] >= 0)], left[1][np.where(left[1] >= 0)]
bright = right[0][np.where(right[1] < dimension)], right[1][np.where(right[1] < dimension)]
btop = top[0][np.where(top[0] >= 0)], top[1][np.where(top[0] >= 0)]
bbottom = bottom[0][np.where(bottom[0] < dimension)], bottom[1][np.where(bottom[0] < dimension)]
field[greater3] -= 4
field[bleft] += 1
field[bright] += 1
field[btop] += 1
field[bbottom] += 1
return (field)
print(abba)
matfig = plt.figure(figsize=(3,3))
plt.matshow(abba, fignum=matfig.number)
n = 0
while (abba < 4).all() == False:
abba = sandpile(abba)
plt.matshow(abba, fignum=matfig.number)
n += 1
print('Exit with',n,'steps')
print(abba)
This is one way you can see an updating plot in a loop:
...
matfig = plt.figure(figsize=(3,3))
ax1 = matfig.add_subplot(1, 1, 1)
ax_image = ax1.imshow(abba)
plt.show(block=False)
n = 0
while (abba < 4).all() == False:
abba = sandpile(abba)
ax_image.remove()
ax_image = ax1.imshow(abba)
matfig.canvas.draw()
matfig.canvas.flush_events()
n += 1
print(n)
print('Exit with',n,'steps')
print(abba)
plt.show(block=True)
In your example changes happens at the very end of the loop.
I am in the middle of making a program that simulates chemical equilibrium. In theory, it is simple, it takes in initial concentrations of A (B is size of grid-A) and a probability of having A (B's probability is 1-A). Then it sets up an n by n grid with the initial conditions; randomly distributing each A. It then simulates what would occur to the concentration over time, but it disregards the initial conditions and calculates from a 1:0 ratio of A:B. I know why it does that, but I do not know how to make my program consider the initial conditions. My code is the following:
n = 100
A=3000
B=(n*n)-A
time = 25
probA = 70 #where probability of getting A is probA/prob
prob = 100
#Specifications
width = 5
height = width
x_position = width
y_position = height
#Functions
concA = []
concB = []
time1 = []
color1=[170,10,0]
color2=[0,170,170]
So far these are just empty lists and constants I need to run the program and display the data I want at the end.
def draw_initial(n):
countA_int=0
countB_int=0
for i in range(n):
for j in range(n):
y = y_position * j
x = x_position * i
r = randint(0,int(A+B))
if r<A:
clr=color1
countA_int +=1
else:
clr=color2
countB_int +=1
rect(x, y, width, height,*clr)
rect(x, y, width, height,*clr)
concA.append(100*countA_int/(n*n))
concB.append(100*countB_int/(n*n))
time1.append(0)
print('Initial concentrations:')
print('A = {} and B = {}'.format(concA[-1],concB[-1]))
wait_mouse_press()
clear()
So far I have made the initial grid. However, I know how to randomly distribute n amount of A in the grid. I just know how to make it so that roughly n percentage of the grid is A. Please instruct me here.
def start_reaction(n):
t = 1
while True:
countA_final = 0
countB_final = 0
for i in range(n):
for j in range(n):
y = y_position * j
x = x_position * i
r = randint(0,prob)
v=(-math.e**(-(1/math.e)*t))+1
if r <= v*probA:
clr = color1
countA_final += 1
else:
clr = color2
countB_final += 1
rect(x, y, width, height,*clr)
rect(x, y, width, height,*clr)
concA.append(100*countA_final/(n*n))
concB.append(100*countB_final/(n*n))
t += 1
time1.append(t-1)
print ('New round, time ={}'.format(t-1))
print('A = {}'.format(concA[-1]))
print('B = {}'.format(concB[-1]))
wait_mouse_press()
if t > time:
break
print(concA)
print(concB)
print(time1)
This next bit calculates how the grid looks for each iteration. It uses an odd formula to model the probability accurately. By the end it shows you this graph:
Clearly, there is an issue. At the very beginning, the data points jump instantly and then are modeled as they should be. The jump occurs because the second function doesn't know how the grid started and instead calculates a grid with only A at first and then does the iterations. I want my program to reach equilibrium from any given concentration, not only from 100% A. Can someone please help me?
Well, maybe it isn't of much interest for people, but I've managed to fix the issue. I won't bother explaining in detail but the issue had to do with the formula I used that modeled the increase or decrease in probability. I created another equation that would yield a variable that would shift the curve to the left in order to match the current concentration. If anyone wants the medialib file in order to run the code yourself, please write it in the comments. The code is the following:
from medialib import *
from random import randint # import randint() function
import matplotlib.pyplot as plt
import math
#Input variables
n = 100
A=1000 #must be between 0 and n*n
B=(n*n)-A
time = 25
probA = 50 #where probability of getting A is probA/prob
prob = 100
#Specifications
width = 5
height = width
x_position = width
y_position = height
#Functions
concA = []
concB = []
time1 = []
color2=[170,10,0]
color1=[0,170,170]
def draw_initial(n):
countA_int=0
countB_int=0
for i in range(n):
for j in range(n):
y = y_position * j
x = x_position * i
r = randint(0,int(A+B))
if r<A:
clr=color1
countA_int +=1
else:
clr=color2
countB_int +=1
rect(x, y, width, height,*clr)
rect(x, y, width, height,*clr)
concA.append(100*countA_int/(n*n))
concB.append(100*countB_int/(n*n))
time1.append(0)
print('Initial concentrations:')
print('A = {} and B = {}'.format(concA[-1],concB[-1]))
wait_mouse_press()
clear()
def start_reaction(n):
t = 1
while True:
countA_final = 0
countB_final = 0
if concA[-1]<probA:
l=math.e*math.log(1/(abs(1-(concA[-1]/probA))))
v=(-math.e**((-1/math.e)*(t+l)))+1
elif concA[-1]==probA:
l=math.e*math.log(1/(abs(1-((concA[-1]+0.1)/probA))))
v=(-math.e**((-1/math.e)*(t+l)))+1
elif concA[-1]>probA:
l=math.e*math.log(1/(abs(1-(concA[-1]/probA))))
v=(math.e**((-1/math.e)*(t+l)))+1
for i in range(n):
for j in range(n):
y = y_position * j
x = x_position * i
r = randint(0,prob)
if r < v*probA:
clr = color1
countA_final += 1
else:
clr = color2
countB_final += 1
rect(x, y, width, height,*clr)
rect(x, y, width, height,*clr)
concA.append(100*countA_final/(n*n))
concB.append(100*countB_final/(n*n))
t += 1
time1.append(t-1)
print ('New round, time ={}'.format(t-1))
print('A = {}'.format(concA[-1]))
print('B = {}'.format(concB[-1]))
wait_mouse_press()
if t > time:
break
print(concA)
print(concB)
print(time1)
draw_initial(n)
start_reaction(n)
wait_mouse_press()
import matplotlib.pyplot as plt
axes = plt.axes()
axes.set_ylim([0, 100])
plt.plot(time1,concA, label="Conc.A")
plt.plot(time1,concB, label="Conc.B")
plt.ylabel('% concentration')
plt.xlabel('time')
plt.show()
wait_mouse_press()
all_done() # always the last instruction of the program
That's the graph, see how the concentrations do not have to begin at 100:0 anymore.
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.
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!
This question already has answers here:
Python equivalent to 'hold on' in Matlab
(5 answers)
Closed 6 years ago.
This has been surprisingly difficult to find information on. I have two functions that I want to chart together, enumeration() and betterEnumeration()
import matplotlib.pyplot as plt
import time
import numpy as np
import sympy
from sympy import S, symbols
import random
from math import floor
def enumeration(array):
max = None
to_return = (max, 0, 0)
for i in range(0, len(array) + 1):
for j in range(0, i):
currentSum = 0
for k in range(j, i):
currentSum += array[k]
if (max is None) or (currentSum > max):
max = currentSum
to_return = (max, j, k)
return to_return
def betterEnumeration(array):
max = None
to_return = (max, 0, 0)
for i in range(1, len(array) + 1):
currentSum = 0
for j in range(i, len(array) + 1):
currentSum += array[j - 1]
if (max is None) or (currentSum > max):
max = currentSum
to_return = (max, i-1, j-1)
return to_return
I also have two helper functions randomArray() and regressionCurve().
def randomArray(totalNumbers,min,max):
array = []
while totalNumbers > 0:
array.append(random.randrange(min,max))
totalNumbers -= 1
return array
def regressionCurve(x,y):
# calculate polynomial
p = np.polyfit(x, y, 3)
f = np.poly1d(p)
# calculate new x's and y's
x_new = np.linspace(x[0], x[-1], 50)
y_new = f(x_new)
x = symbols("x")
poly = sum(S("{:6.5f}".format(v))*x**i for i, v in enumerate(p[::-1]))
eq_latex = sympy.printing.latex(poly)
plt.plot(x_new, y_new, label="${}$".format(eq_latex))
plt.legend(fontsize="small")
plt.show()
I want to plot both of these functions on the same chart, both the raw data points as well as the regression curves. The following code will chart the data points for enumeration() and then make a regression curve for them, but I'm not sure how to plot both enumeration() and betterEnumeration() on the same chart.
def chart():
nValues = [10,25,50,100,250,500,1000]
avgExecTimes = []
for n in nValues: # For each n value
totals = []
sum = 0
avgExecTime = 0
for i in range(0,10): # Create and test 10 random arrays
executionTimes = []
array = randomArray(n,0,10)
t1 = time.clock()
enumeration(array)
t2 = time.clock()
total = t2-t1
totals.append(total)
executionTimes.append(total)
print("Time elapsed(n=" + str(n) + "): " + str(total))
for t in totals: # Find avg running time for each n's 10 executions
sum += t
avgExecTime = sum/10
avgExecTimes.append(avgExecTime)
print("Avg execution time: " + str(avgExecTime))
# Chart execution times
plt.plot(nValues,avgExecTimes)
plt.ylabel('Seconds')
plt.xlabel('n')
plt.show()
# Chart curve that fits
x = np.array(nValues)
y = np.array(avgExecTimes)
regressionCurve(x,y)
To add a line to a plot:
plt.plot(x,y)
so, if you wanted to plot x1, y1 and then add x2,y2:
plt.plot(x1,y1)
plt.plot(x2,y2)
However, that's going to plot the second line in the default color. You're going to want to add a color component:
plt.plot(x1,y1, c='b')
plt.plot(x2,y2, c= 'g')
and if the units are different, you'll want to look into twinx, which will allow you to plot with 2 different y axes but the same x axis.
You're going to want to plot both sets of data from within the same function or both outside of the function. Otherwise, you're running into a local vs. global issue as well.