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]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With