I just started learning Python in a while, so we have to do this homework, which writes a program to run the Conway's Game of Life using matplotlib. My professor has done part of codes and we have to fill the code under the TODO comments. So I wrote it, and I didn't know why it didn't run the animation. What had I done wrong? Thanks so much guys !!! The comments in the program are pretty long since they are kind of instructions.
# life.py - Once complete, this program will play the game of
# life.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
# The update function is needed for the animation
# to work properly. It has four parameters:
# frameNum - this is handled by the animation, don't change this.
# img - the plot that is passed and changed, don't change this.
# world - the two-D array that represents the world for the
# game of life. This will be updated to the next gen.
# N - the size of the world (which is square).
def update( frameNum, img, world, N ) :
newWorld = world.copy( )
## TODO - Write code here to update the cells in newWorld
## for the next generation of life. Remember to
## use the toroidal model. Rather than making
## special cases for row/column 0 and N-1, just
## use the % operator.
for i in range (N):
for j in range (N):
total= (world[(i-1)%N][(j-1)%N]+world[(i-1)%N][j]+world[(i-1)%N][(j+1)%N]+
world[i][(j-1)%N]+world[i][(j+1)%N]+ world[(i+1)%N][(j-1)%N]+
world[(i+1)%N][j]+ world[(i+1)%N][(j+1)%N])/255
if world[i][j]== 255:
if total>3 or total<2:
newWorld[i][j]== 0
elif total==3:
newWorld[i][j]== 255
img.set_data( newWorld )
world[:] = newWorld[:]
return img
N = 50
SPEED = 100
PROB_LIFE = 40
## TODO - Write code here to create the initial population
## of the world. I recommend creating an N x N array that
## is initially filled with random numbers from 0 to 99.
## Then use the PROB_LIFE to change the entries to be
## either alive (255) or dead (0).
world= np.random.choice([0,255], N*N, p=[1-((PROB_LIFE)/100),(PROB_LIFE)/100]).reshape(N,N)
fig, ax = plt.subplots( )
img = ax.imshow( world, interpolation='nearest' )
ani = animation.FuncAnimation( fig, update, fargs = ( img, world, N ),
frames = 10, interval = SPEED,
save_count = 50 )
plt.show( )
# This is the end of the program. You should not need
# anything after this point.
You have to use = instead of == to assign new values in
newWorld[i][j] = 0 # need `=` instead of `==
newWorld[i][j] = 255 # need `=` instead of `==
and now you will see animation.
But you have also mistake with elif - wrong indention - correctly
if world[i][j] == 255:
if total > 3 or total < 2:
newWorld[i][j] = 0
elif total == 3:
newWorld[i][j] = 255
or more readable
if world[i][j] == 255:
if total > 3 or total < 2:
newWorld[i][j] = 0
else:
if total == 3:
newWorld[i][j] = 255
Related
Let me preface this by letting everyone know that I'm still somewhat new to programming, so I'm sure my code's probably fairly inefficient in some parts with some potentially cringeworthy lines. I apologize in advance.
Anyways, I'm trying to program a 2D physics simulator that simulates the interaction between two celestial bodies given a set of initial conditions, and then animates their trajectories. The problem is, when I run my code, I get the following error: AttributeError: 'list' object has no attribute 'set_data', specifically citing the line.set_data([],[]) command in init(). This error points at line 61, which I've marked below (I cut out some unnecessary comments & definitely messed up the line numbers for the code snippet you're seeing below). Here is my code:
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation
# ->> Initialize Figure <<-
fig = plt.figure() # creates figure window
ax = plt.axes(xlim=(x[0],x[-1]),ylim=(y[0],y[-1])) # creates axis object
plotColors = ("blue","red","green","black") # colors to use in plots (qty. must match or exceed numBodies)
line, = ax.plot([],[],lw=2) # creates blank line object
lines = [] # list that contains line objects for simulated bodies
numBodies = 2 # number of bodies to intitialize (not necessarily simulate)
numArgs = 2 # DO NOT CHANGE: number of bodies to simulate
xBody1,xBody2 = [],[] # tracks x-coordinates for both simulated bodies
yBody1,yBody2 = [],[] # tracks y-coordinates for both simulated bodies
print("-- One --")
# ->> Initialize list of line objects for all bodies <<-
for i in range(numArgs):
line_obj = ax.plot([],[],lw=2,color=plotColors[i])
lines.append(line_obj)
print("-- Two --")
# ->> Initialize Animation Frame Initialization Function <<-
def init():
for line in lines:
line.set_data([],[]) #............................................<<<<<<< LINE 61 <<<<<<<
return lines
print("-- Three --")
# ->> Initialize Animation Function (called sequentially) <<-
def animate(i):
xList = [xBody1,xBody2] # contains x-coordinate data for each body
yList = [yBody1,yBody2] # contains y-coordinate data for each body
for num,line in enumerate(lines): # for index in range(0,1):
line.set_data(xList[num],yList[num]) # set data for each line separately
plt.pause(0.1)
return lines
# ->> Initialize Numerical Calculation Sequence <<-
def calculate(lastP,lastV,lastA): # calculates each iteration of movements
x1 = lastP[0] + lastV[0]*dt + 0.5*lastA[0]*np.square(dt)
y1 = lastP[1] + lastV[1]*dt + 0.5*lastA[1]*np.square(dt)
x2 = lastP[2] + lastV[2]*dt + 0.5*lastA[2]*np.square(dt)
y2 = lastP[3] + lastV[3]*dt + 0.5*lastA[3]*np.square(dt)
vx1 = lastV[0] + lastA[0]*dt
vy1 = lastV[1] + lastA[1]*dt
vx2 = lastV[2] + lastA[2]*dt
vy2 = lastV[3] + lastA[3]*dt
fx1 = G*m1*m2/np.square(x2-x1)
fy1 = G*m1*m2/np.square(y2-y1)
fx2 = G*m1*m2/np.square(x1-x2)
fy2 = G*m1*m2/np.square(y1-y2)
ax1 = fx1/m1
ay1 = fy1/m1
ax2 = fx2/m2
ay2 = fy2/m2
pos = [x1,y1,x2,y2]
vel = [vx1,vy1,vx2,vy2]
force = [fx1,fy1,fx2,fy2]
acc = [ax1,ay1,ax2,ay2]
return pos,vel,force,acc
# ->> Initialize Simulation Function
def simulate(sPos,sVel,sAcc): # handles calculations & data management for animation
xx1,xx2 = [],[]
yy1,yy2 = [],[]
xx1.append(sPos[0])
yy1.append(sPos[1])
xx2.append(sPos[2])
yy2.append(sPos[3])
Pos,Vel,Force,Acc = calculate(sPos,sVel,sAcc)
for t in range(N):
lastPos = Pos
lastVel = Vel
lastAcc = Acc
Pos,Vel,Force,Acc = calculate(lastPos,lastVel,lastAcc)
xx1.append(Pos[0])
yy1.append(Pos[1])
xx2.append(Pos[2])
yy2.append(Pos[3])
return xx1,yy1,xx2,yy2
print("-- Four --")
# ->> Specify Simulation Quantities <<-
G = 1 # gravitational constant (actually equals 6.67430e-11)
tmin = 0
tmax = 10000
N = 20000
dt = (tmax-tmin)/N
# ->> Specify Initial Conditions <<-
m1 = 1000 # mass of body 1 (kg)
m2 = 1000 # mass of body 2 (kg)
x1s = 10 # starting x-coordinate of body 1
y1s = 90 # starting y-coordinate of body 1
x2s = 90 # starting x-coordinate of body 2
y2s = 10 # starting y-coordinate of body 2
fx1s = 0 # initial x-directed force on body 1 (N) at t=0-
fy1s = 0 # initial y-directed force on body 1 (N) at t=0-
fx2s = 0 # initial x-directed force on body 2 (N) at t=0-
fy2s = 0 # initial y-directed force on body 2 (N) at t=0-
ax1s = fx1s/m1 # initial x-acceleration of body 1 (m/s^2)
ay1s = fy1s/m1 # initial y-acceleration of body 1 (m/s^2)
ax2s = fx2s/m2 # initial x-acceleration of body 2 (m/s^2)
ay2s = fy2s/m2 # initial y-acceleration of body 2 (m/s^2)
vx1s = 0 # initial x-velocity of body 1 (m/s)
vy1s = 0 # initial y-velocity of body 1 (m/s)
vx2s = 0 # initial x-velocity of body 2 (m/s)
vy2s = 0 # initial y-velocity of body 2 (m/s)
# ->> Initialize Physics Vectors <<-
mass = [m1,m2]
Pos = [x1s,y1s,x2s,y2s]
xPos = [x1s,x2s]
yPos = [y1s,y2s]
Force = [fx1s,fy1s,fx2s,fy2s]
xForce = [fx1s,fx2s]
yForce = [fy1s,fy2s]
Acc = [ax1s,ay1s,ax2s,ay2s]
xAcc = [ax1s,ax2s]
yAcc = [ay1s,ay2s]
Vel = [vx1s,vy1s,vx2s,vy2s]
xVel = [vx1s,vx2s]
yVel = [vy1s,vy2s]
simulate(Pos,Vel,Acc)
print(type(line))
print("-- Five --")
# ->> ANIMATE SIMULATION <<-
anim = animation.FuncAnimation(fig, animate, init_func=init,
frames=200, interval=20, blit=True)
#anim.save('basic_animation.mp4', fps=30, extra_args=['-vcodec', 'libx264'])
plt.show()
Here's what's messing me up: I know this error is usually given when you "fail to unpack the list of Line2D object", as mentioned in the answer to this question. To solve this, you should include a comma next to the variable you're trying to "unpack". In this case, when I initialized line towards the top of my code snippet, I definitely included that comma. So I'm very confused as to why I'm getting this error message? For reference, I've been following this example for creating the animated plot, and I believe I've been consistent with their code for the most part.
Moreover, I created a few print() statements to help me see various stages of the code's execution. This is what the output looks like before the error message:
-- One --
-- Two --
-- Three --
-- Four --
<class 'matplotlib.lines.Line2D'>
-- Five --
As you can see, the line variable is of type lines.Line2D right before the simulation begins, which should be exactly what we want (right?). My suspicion is that there's something weird going on under the hood once simulation() is called, but I'm not competent enough to navigate this process.
Can anyone help me figure out what's going wrong in my code? Thanks.
I have made a class which initiates and updates the CA data, and I have made a function 'Simulate' which updates the cells based on the rule that fire spreads across trees, and leaves empty spaces. Empty spaces are replaced with trees based on a given probability.
There is a problem where it appears my function is applying the rule to the current time data holder, rather than the previous time data holder. I have set prevstate = self.state to act as a temporary data holder for the previous iteration, but running small tests I find that it gives the same results as if I didn't include this line at all. What am I doing wrong?
import numpy as np
import random
import matplotlib.pyplot as plt
from matplotlib.colors import LinearSegmentedColormap, colorConverter
from matplotlib.animation import FuncAnimation
#dimentions:
x = 10
y = 10
lighting = 0 #set to 0 for testing
grow = 0.3
#parameter values
empty = 0
tree = 1
fire = 2
random.seed(1)
#CA Rule definition
def update(mat, i, j, lighting, grow, prob):
if mat[i, j] == empty:
if prob < grow:
return tree
else:
return empty
elif mat[i, j] == tree:
if max(mat[i-1, j], mat[i+1, j], mat[i, j-1], mat[i, j+1]) == fire:
return fire
elif prob < lighting:
return fire
else:
return tree
else:
return empty
########## Data Holder
class Simulation:
def __init__(self):
self.frame = 0
#self.state = np.random.randint(2, size=(x, y)) commented out for testing
self.state = np.ones((x, y))
self.state[5, 5] = 2 #initial fire started at this location for testing
def updateS(self):
prevstate = self.state #line of code i think should be passing previous iteration through rule
for i in range(1, y-1):
for j in range(1, x-1):
prob = random.random()
self.state[i, j] = update(prevstate, i, j, lighting, grow, prob)
def step(self):
self.updateS()
self.frame += 1
simulation = Simulation()
figure = plt.figure()
ca_plot = plt.imshow(simulation.state, cmap='seismic', interpolation='bilinear', vmin=empty, vmax=fire)
plt.colorbar(ca_plot)
transparent = colorConverter.to_rgba('black', alpha=0)
#wall_colormap = LinearSegmentedColormap.from_list('my_colormap', [transparent, 'green'], 2)
def animation_func(i):
simulation.step()
ca_plot.set_data(simulation.state)
return ca_plot
animation = FuncAnimation(figure, animation_func, interval=1000)
mng = plt.get_current_fig_manager()
mng.window.showMaximized()
plt.show()
Any comments on better ways to implement a CA are most welcome!
Python assignments are pointers... So when you update self.state, then prevstate is also updated.
I expect if you set to:
prevstate = copy.copy(self.state)
That should fix your problem.
Copy docs
As jabberwocky correctly notes, your problem is that the line prevstate = self.state makes prevstate a new reference to the same numpy array as self.state, so that modifying the contents of one also modifies the other.
Instead of copying the array on every iteration, however, a slightly more efficient solution would be to preallocate two arrays and swap them, something like this:
class Simulation:
def __init__(self):
self.frame = 0
self.state = np.ones((x, y))
self.state[5, 5] = 2
self.prevstate = np.ones((x, y)) # <-- add this line
def updateS(self):
self.state, self.prevstate = self.prevstate, self.state # <-- swap the buffers
for i in range(1, y-1):
for j in range(1, x-1):
prob = random.random()
self.state[i, j] = update(self.prevstate, i, j, lighting, grow, prob)
I say "slightly" because all you're really saving is a numpy array copy and some work for the garbage collector. However, if you optimize your inner state update loop enough — maybe e.g. implementing the CA rule using numba — the relative cost of an extra array copy will start to be significant. In any case, there are no real down sides to using this "double buffering" method, so it's a good habit to pick up.
This question is probably very simple but for the life of me I can't figure it out. Basically, I have a neuron whose voltage I'm modeling, but I have it receiving input spikes from other neurons randomly. So a friend of mine helped to create a function that essentially has some excitatory neurons provide a random Poisson spike which increases the voltage randomly and some inhibitory neurons providing downward spikes lowering the voltage. I've included the code below. Basically the step I'm trying to figure out how to do is how to make the I_syn term in the iterative step work. I would normally think to just write I_syn[i-1], but that gives me an error:
'function' object has no attribute '__getitem__'.
So I'm sure this question is really simple, but it's a problem I don't know how to overcome. How do I get this program to iterate the I_syn term properly so I can do a basic iterative scheme of an ODE while including a function defined previously in the code? It's important because I'll likely have more complicated neuron equations in the near future, so it would be much better to write the functions beforehand and then call them into the iteration step as needed. Thank you!
from numpy import *
from pylab import *
## setup parameters and state variables
T = 50 # total time to simulate (msec)
dt = 0.125 # simulation time step (msec)
time = arange(0, T+dt, dt) # time array
t_rest = 0 # initial refractory time
## LIF properties
Vm = zeros(len(time)) # potential (V) trace over time
Rm = 1 # resistance (kOhm)
Cm = 10 # capacitance (uF)
tau_m = Rm*Cm # time constant (msec)
tau_ref = 4 # refractory period (msec)
Vth = 1 # spike threshold (V)
V_spike = 0.5 # spike delta (V)
## Stimulus
I = 1.5 # input current (A)
N = 1000
N_ex = 0.8*N #(0..79)
N_in = 0.2*N #(80..99)
G_ex = 0.1
K = 4
def I_syn(spks, t):
"""
Synaptic current
spks = [[synid, t],]
"""
if len(spks) == 0:
return 0
exspk = spks[spks[:,0]<N_ex] # Check for all excitatory spikes
delta_k = exspk[:,1] == t # Delta function
if np.any(delta_k) > 0:
h_k = np.random.rand(len(delta_k)) < 0.90 # probability of successful transmission
else:
h_k = 0
inspk = spks[spks[:,0] >= N_ex] #Check remaining neurons for inhibitory spikes
delta_m = inspk[:,1] == t #Delta function for inhibitory neurons
if np.any(delta_m) > 0:
h_m = np.random.rand(len(delta_m)) < 0.90
else:
h_m = 0
isyn = C_m*G_ex*(np.sum(h_k*delta_k) - K*np.sum(h_m*delta_m))
return isyn
## iterate over each time step
for i, t in enumerate(time):
if t > t_rest:
Vm[i] = Vm[i-1] + (-Vm[i-1] + I_syn*Rm) / tau_m * dt
if Vm[i] >= Vth:
Vm[i] += V_spike
t_rest = t + tau_ref
## plot membrane potential trace
plot(time, Vm)
title('Leaky Integrate-and-Fire Example')
ylabel('Membrane Potential (V)')
xlabel('Time (msec)')
ylim([0,2])
show()
I_syn is just a function so using I_syn[i-1] will throw this error:
'function' object has no attribute '__getitem__'
If what you are looking for is a return value from the function, then you should first call it and then access what you want.
# pass related arguments as well since the function expects it
I_syn(arg1, arg2)[i-1]
I am attempting to create a "rolling spline" using polynomials via polyfit and polyval.
However I either get an error that "offset" is not defined... or, the spline doesn't plot.
My code is below, please offer suggestions or insights. I am a polyfit newby.
import numpy as np
from matplotlib import pyplot as plt
x = np.array([ 3893.50048173, 3893.53295003, 3893.5654186 , 3893.59788744,
3893.63035655, 3893.66282593, 3893.69529559, 3893.72776551,
3893.76023571, 3893.79270617, 3893.82517691, 3893.85764791,
3893.89011919, 3893.92259074, 3893.95506256, 3893.98753465,
3894.02000701, 3894.05247964, 3894.08495254])
y = np.array([ 0.3629712 , 0.35187397, 0.31805825, 0.3142261 , 0.35417492,
0.34981215, 0.24416184, 0.17012087, 0.03218199, 0.04373861,
0.08108644, 0.22834105, 0.34330638, 0.33380814, 0.37836754,
0.38993407, 0.39196328, 0.42456769, 0.44078106])
e = np.array([ 0.0241567 , 0.02450775, 0.02385632, 0.02436235, 0.02653321,
0.03023715, 0.03012712, 0.02640219, 0.02095554, 0.020819 ,
0.02126918, 0.02244543, 0.02372675, 0.02342232, 0.02419184,
0.02426635, 0.02431787, 0.02472135, 0.02502038])
xk = np.array([])
yk = np.array([])
w0 = np.where((y<=(e*3))&(y>=(-e*3)))
w1 = np.where((y<=(1+e*3))&(y>=(1-e*3)))
mask = np.ones(x.size)
mask[w0] = 0
mask[w1] = 0
for i in range(0,x.size):
if mask[i] == 0:
if ((abs(y[i]) < abs(e[i]*3))and(abs(y[i])<(abs(y[i-1])-abs(e[i])))):
imin = i-2
imax = i+3
if imin < 0:
imin = 0
if imax >= x.size:
imax = x.size
offset = np.mean(x)
for order in range(20):
coeff = np.polyfit(x-offset,y,order)
model = np.polyval(coeff,x-offset)
chisq = ((model-y)/e)**2
chisqred = np.sum(chisq)/(x.size-order-1)
if chisqred < 1.5:
break
xt = x[i]
yt = np.polyval(coeff,xt-offset)
else:
imin = i-1
imax = i+2
if imin < 0:
imin = 0
if imax >= x.size:
imax = x.size
offset = np.mean(x)
for order in range(20):
coeff = np.polyfit(x-offset,y,order)
model = np.polyval(coeff,x-offset)
chisq = ((model-y)/e)**2
chisqred = np.sum(chisq)/(x.size-order-1)
if chisqred < 1.5:
break
xt = x[i]
yt = np.polyval(coeff,xt-offset)
xk = np.append(xk,xt)
yk = np.append(yk,yt)
#print order,chisqred
################################
plt.plot(x,y,'ro')
plt.plot(xk+offset,yk,'b-') # This is the non-plotting plot
plt.show()
################################
Update
So I edited the code, removing all of the if conditions that do not apply to this small sample of data.
I also added the changes that I made which allow the code to plot the desired points... however, now that the plot is visible, I have a new problem.
The plot isn't a polynomial of the order the code is telling me it should be.
Before the plot command, I added a print, to display the order of the polynomial and the chisqred, just to be certain that it was working.
First, thank you for providing a self-contained sample (not many newbies do that)! If you want to improve your question, you should remove all debugging code from the sample, as now it clutters the code. The code is quite long and not very self-explanatory. (At least to me - the problem may be between my ears, as well.)
Let us unroll the problem from the end. The proximal reason why you get an empty plot is that you have empty xkand yk (empty arrays).
Why is that? That is because you have 19 points, and thus your for loop is essentially:
for i in range(12, 19-1-12):
...
There is nothing to iterate from 12..6! So actually your loop is run through exactly zero times and nothing is ever appended to xk and yk.
The same explanation explains the problem with offset. If the loop is never run through, there is no offset defined in yout plot command (xk+offset), hence the NameError.
This was the simple part. However, I do not quite understand your code. Especially the loops where you loop order form 0..19 look strange, as only the result form the last cycle will be used. Maybe there is something to fix?
(If you still have problems with the code after this analysis, please fix the things you can, simplify the code as much as possible, and edit your question. Then we can have another look into this!)
I made a progress meter in web2py, but it only shows up in the terminal window. How can I make the progress bar/meter to work in the web2py's HTML page?
Here's a part of the code:
k = 1 # This is the loop variable for subplots.
for counter in nus:
fig = plt.figure()
D = E*(h**3)/(12*(1-counter**2)) # Cylindrical rigidity.
T0 = (L**2)/(D*np.pi**2)*T0_orig # Nondimensional tension.
amax = T0/kappa # Maximum allowed alpha (to keep tension nonnegative everywhere).
alphas = [0, (10**-6)*amax, (10**-4)*amax, (10**-2)*amax] # Nondimensional alphas to use for plot.
workdone = 0.0 # How much of the Figure has been calculated? 0.0 = none, 1.0 = Figure is ready to show.
workstep = 100.0/len(alphas) # How much work is done during one step in the loop? If there are 4 steps in the loop, then then step will be 100.0/4 = 25.0.
for alpha in alphas:
lambda_, xx, f = nonhomog_solver(kappa, alpha, nu, nx)
V0 = np.sqrt( T0_orig/m + np.pi**2 * D/(m*L**2)*lambda_ )
if (k == 1):
V0_ref = V0
# Figure 1
fig_a = fig.add_subplot(2,2,k)
fig.subplots_adjust(hspace=0.4)
if (k == 1):
fig_a.set_title(r'$\alpha / \alpha_{max} = %.2g, V_{0}^{ref} = %.6g$ m/s' % (alpha/amax, V0))
else:
fig_a.set_title(r'$\alpha / \alpha_{max} = %.2g, V_{0}/V_{0}^{ref} = %.6g$' % (alpha/amax, V0/V0_ref))
fig_a.plot(xx,f)
plt.xlim(-kappa,kappa)
plt.xlabel(r'$\eta$')
plt.ylim(-0.1,1.1)
if ((k == 1) or (k == 3)):
plt.ylabel(r'$f(\eta)$')
workdone = workdone + workstep
print "Figure 1:", workdone, "%/100.0% done."
# Let's get ready for the next subfigure.
k = k + 1
You might be better off asking the mailing list.
Is your code inside (or called by) a controller function? Note, print statements don't send any output to web pages (i.e., they don't affect the HTTP response) -- to do that, your controller needs to return a dict to a view (or return a string). For a progress bar, you may end up needing to use Ajax (also, see here).
This Client Tools module has a progress bar example (scroll to the "Even more examples" section). I haven't used it and am not sure it fits your use case, but it may give you some ideas.