1

I'm working on learning python more in depth than from my previous questions now that my internship is over and I hit an issue

I'm using a book "Doing Math With Python" by Amit Saha which what I decided to jump to was 'Animating a Projectile's Trajectory. I spent an hour trying to figure it out on my own then another 2 days on the internet and I still can't understand why I'm getting the error I'm getting

AttributeError: 'float' object has no attribute 'append'

if I don't have the float in the code then it doesn't work at all and I get this

TypeError: a float is required

I want to get this project done hopefully before we leave the projectile motion unit in my high school physics just as a cool thing I learned to do. please help. I can get it to draw the trajectory, just not animate it :(

from matplotlib import pyplot as plt
from matplotlib import animation
import math

g = 9.8

def get_intervals(u, theta):

    t_flight = 2*u*math.sin(theta)/g
    intervals = []
    start = 0
    intervals = 0.005
    while start < t_flight:
        intervals.append(start)
        start = start + interval
    return intervals

def update_position(i, circle, intervals, u, theta):

    t = intervals[i]
    x = u*math.cos(theta)*t
    y = u*math.sin(theta)*t - 0.5*g*t*t
    circle.center = x, y
    return circle,

def create_animation(u, theta):

    intervals = get_intervals(u,theta)

    xmin = 0
    xmax = u*math.cos(theta)*intervals[-1]
    ymin = 0
    t_max = u*math.sin(theta)/g
    ymax = u*math.sin(theta)*t_max - 0.5*g*t_max**2
    fig = plt.gcf()
    ax = plt.axes(xlim=(xmin, xmax), ylim=(ymin, ymax))

    circle = plt.Circle((xmin, ymin), 1.0)
    ax.add_patch(circle)
    anim = animation.FuncAnimation(fig, update_position,
                        fargs=(circle, intervals, u, theta),
                        frames=len(intervals), interval=1,
                        repeat=False)

    plt.title('Projectile Motion')
    plt.xlabel('X')
    plt.ylabel('Y')
    plt.show()

if __name__ == '__main__':
    try:
        u = float(input('Enter the initial velocity (m/s): '))
        theta = float(input('Enter the angle of projection (degrees): '))
    except ValueError:
        print('You Entered an invalid input')
    else:
        theta = (math.radians(theta))
        create_animation(u, theta)
1
  • 2
    well in get_intervals you write: intervals=0.005 then intervals.append(.... No wonder this does not work. Just remove the s in intervals=0.005. Commented Nov 7, 2016 at 16:42

1 Answer 1

3

Your code is very close! Right now there is an error based on the variable intervals being defined twice and the variable interval never being defined. So change intervals = 0.005 to interval = 0.005 as in the following code:

def get_intervals(u, theta):

    t_flight = 2*u*math.sin(theta)/g
    intervals = []
    start = 0
    interval = 0.005
    while start < t_flight:
        intervals.append(start)
        start = start + interval
    return intervals

Now the code will run but the plot will look very different for various velocities and thetas. In fact for many initial conditions, you will only see a plot of blue. Let's look at the problems one by one:

  1. The radius of the ball, rad, is 1 m. If the ball travels less than 1 m in the x-direction or y-direction, the the blue ball will dominate the screen.
  2. The x-axis and y-axis have very different sizes and scales. This will make the ball an oblong oval rather than a circle.

I changed your create_animation() function to fix these small issues. Please read the comments I've placed to understand the subtle changes

def create_animation(u, theta):
    intervals = get_intervals(u,theta)

    xmin = 0
    xmax = u*math.cos(theta)*intervals[-1]
    ymin = 0
    t_max = u*math.sin(theta)/g
    ymax = u*math.sin(theta)*t_max - 0.5*g*t_max**2

    plotmax = max(xmax, ymax) # Pick the largest dimension of the two
    fig = plt.gcf()

    # Set both maxima to the same value to make a square plot
    ax = plt.axes(xlim=(xmin, plotmax), ylim=(ymin, plotmax)) 

    # Make sure the two axes are scaled the same...
    #    (we want a circle.. not a messed up oval)
    ax.set_aspect('equal')


    rad = plotmax/20. # Make sure the circle doesn't dominate the plot

    circle = plt.Circle((xmin, ymin), rad) # Use rad instead of 1.0
    ax.add_patch(circle)
    anim = animation.FuncAnimation(fig, update_position,
                        fargs=(circle, intervals, u, theta),
                        frames=len(intervals), interval=1,
                        repeat=False)

    plt.title('Projectile Motion')
    plt.xlabel('X [m]') # Units are nice :)
    plt.ylabel('Y [m]')
    plt.show()
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.