I'm trying to animate a projectile motion path using Python. To achieve this I'm using matplotlib's animation module. My full script is below.
#!/usr/bin/env python
import math
import sys
import matplotlib.animation as anim
from matplotlib.pyplot import figure, show
# Gravitational acceleration in m/s/s
g = -9.81
# Starting velocity in m/s.
vel = 100
# Starting angle in radians.
ang = 45 * math.pi / 180
# Starting height in m.
y0 = 0
# Time settings.
t = 0
dt = 0.1
time = -vel**2 * math.sin(2 * ang) / g
def projectile():
print g, vel, ang, y0, dt, time
print t # Crashes here with UnboundLocalError: local variable 't' referenced before assignment
t=0 # With this it works
x = 0
y = 0.1
xc = []
yc = []
# Simulate the projectile.
while t < time:
x = vel * math.cos(ang) * t
y = vel * math.sin(ang) * t + (g * t**2) / 2 + y0
if y < 0:
break
t += dt
xc.append(x)
yc.append(y)
yield x, y
def update_frame(sim):
x, y = sim[0], sim[1]
line.set_data(x, y)
return line,
def init():
line.set_data([], [])
return line,
# Show the results.
fig = figure()
ax = fig.add_subplot(111)
ax.set_xlim([-5,1500])
ax.set_ylim([0,300])
# ax.plot returns a single-element tuple, hence the comma after line.
line, = ax.plot([], [], 'ro', ms=5)
ani = anim.FuncAnimation(fig=fig, func=update_frame, frames=projectile, blit=True, interval=20, init_func=init, repeat=False)
show()
The problem I have is that I seem to be able to use every variable, except t
. I did it to create a stop condition so it would run only once and I later found out about repeat=False
, but I'm still curious about this. Why can't I use t
inside projectile
? I am running Python 2.7.6 with Matplotlib 1.3.1 from the Anaconda 1.9.1 package.
The problem arises because you try to reassign the global variable t
.
The variables g, vel, ang, y0, dt, time
you only access (without reassigning them), so python tries to access them both locally and then globally. However, when you reassign t
with the line t += dt
, you are really telling python to create a local variable with the identifier t
and assign it the desired value. Therefore, the global identifier t
cannot be accessed as you've told python that t
is local, and when you try to access t
before it is assigned, you the UnboundLocalError
is raised.
To tell python to reassign t
as a global variable, you simply need to add global t
to the beginning of your function:
t = 0
(..)
def projectile():
print g, vel, ang, y0, dt, time
global t # now t can be edited as a global variable
print t #works
x = 0
y = 0.1
xc = []
yc = []
while t < time:
(..)
t += dt
EDIT:
As flebool pointed out, you can actually still change a global variable as long as you don't reassign the identifier for it. For example, the code below is valid:
>>> l = [1,2,3]
>>> def changelist():
... l.append(4)
...
>>> changelist()
>>> l
[1,2,3,4]
Collected from the Internet
Please contact [email protected] to delete if infringement.
Comments