I am trying to animate a simple Projectile motion. In this type of motion, the value of the horizontal range (R = v^2*sin(2 * theta)/g) is the same for angles 30 and 60 degrees. Although I was able to display this value in a dynamic text annotation in my code, I am not getting the same value in the plot title. I believe there is an issue with how I am updating the value of x in the title, but I am unable to figure it out.
I have attached the code and the figure that I received. Can anyone please assist me with this issue?
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
import numpy as np
from math import *
fig = plt.figure(figsize=(10, 6))
ax = fig.add_subplot()
# Constants
g = 10
v = 40 # velocity of projection
# Function to animate projectile motion for given angles
def animate(angles):
ax.clear()
# Calculating time of flight, range, and maximum height for each angle
tms = [(2*v*sin(np.deg2rad(angle))/g) for angle in angles]
Rs = [v**2*sin(2*np.deg2rad(angle))/g for angle in angles]
Hms = [(v*sin(np.deg2rad(angle)))**2/(2*g) for angle in angles]
# Initializing lists to store x and y points for each angle
x_points = [[] for _ in range(len(angles))]
y_points = [[] for _ in range(len(angles))]
# Creating lines for each angle
lines = [ax.plot([], [], color='C'+str(i), ls='-', lw=1, label=f'Angle of projection = {angle}°')[0] for i, angle in enumerate(angles)]
# Create markers for each angle
markers = [ax.scatter([], [], color='C'+str(i), edgecolor='black', alpha=1) for i in range(len(angles))]
# Creating vertical lines to indicate x position
vertical_lines = [ax.plot([], [], color='black', ls='--', lw=0.5, alpha=0.5)[0] for _ in range(len(angles))]
# Creating horizontal lines to indicate y position
horizontal_lines = [ax.plot([], [], color='black', ls='--', lw=0.5, alpha=0.5)[0] for _ in range(len(angles))]
# Creating text annotations for x and y positions
texts1 = [ax.text(0, 0, '', ha='left', va='bottom', fontsize=8) for _ in range(len(angles))]
texts2 = [ax.text(0, 0, '', ha='center', va='bottom', fontsize=8) for _ in range(len(angles))]
def update(t):
for i, angle in enumerate(angles):
if t <= tms[i]:
x = v * cos(np.deg2rad(angle)) * t
y = v * sin(np.deg2rad(angle)) * t - 0.5 * g * t**2
x_points[i].append(x)
y_points[i].append(y)
lines[i].set_data(x_points[i], y_points[i])
markers[i].set_offsets([[x, y]])
vertical_lines[i].set_data([x, x], [0, y])
horizontal_lines[i].set_data([0, x], [y, y])
texts1[i].set_text(f'y = {y:.2f}m')
texts1[i].set_position((x+1, y+0.5))
texts2[i].set_text(f'x = {x:.2f}m')
texts2[i].set_position((x/2, y))
else:
x = v * cos(np.deg2rad(angle)) * tms[i]
y = v * sin(np.deg2rad(angle)) * tms[i] - 0.5 * g * tms[i]**2
lines[i].set_data(x_points[i] + [x], y_points[i] + [y])
markers[i].set_offsets([[x, y]])
markers[i].set_offsets([[x, y]])
vertical_lines[i].set_data([x, x], [0, y])
horizontal_lines[i].set_data([0, x], [y, y])
texts1[i].set_text(f'y = {y:.2f}m')
texts1[i].set_position((x+1, y+0.5))
texts2[i].set_text(f'x = {x:.2f}m')
texts2[i].set_position((x/2, y))
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_title(', '.join([f'R_{angle}= {x:.2f}m, T_{angle}= {t if t <= tm else tm:.2f}s'
for angle, x, tm in zip(angles, [x_points[i][-1] for i in range(len(angles))], tms)]),
fontsize=8)
ax.set_xlim(0, max(Rs) + 5)
ax.set_ylim(-5, max(Hms) + 5)
ax.legend(loc='upper right', fontsize=7)
return lines + markers + vertical_lines + horizontal_lines + texts1 + texts2
anim = FuncAnimation(fig, update, frames=np.linspace(0, max(tms), 50), interval=100, repeat=True)
return anim
fig.suptitle(f'Projectile Motion of particles projected with velocity {v}m/s')
# List of angles for which projectile motion will be animated
angles = [15, 30, 60]
anim = animate(angles)
plt.show()