codexkinetic-energy-work-and-power.py
kinetic-energy-work-and-power.py
"""Draw the ideal constant-force example; write the PNG basename to cwd.
Tested with Python 3.14.4, NumPy 2.3.5, Matplotlib 3.10.7.
All curves are exact expressions for a 2 kg point mass initially at rest.
"""
import matplotlib.pyplot as plt
import numpy as np
def main():
plt.rcParams.update({"font.size": 12, "savefig.facecolor": "white"})
mass, force, distance = 2.0, 3.0, 4.0
acceleration = force / mass
final_time = np.sqrt(2 * distance / acceleration)
x = np.linspace(0, distance, 401)
velocity = np.sqrt(2 * force * x / mass)
energy = force * x
t = np.linspace(0, final_time, 401)
power = force * acceleration * t
mean_power = force * distance / final_time
fig, axes = plt.subplots(1, 3, figsize=(12, 5.2), facecolor="white")
fig.subplots_adjust(left=0.065, right=0.975, bottom=0.19, top=0.73, wspace=0.37)
fig.suptitle("One constant force: motion, energy, and transfer rate", fontsize=18, y=0.97)
fig.text(0.5, 0.865, "Mass 2 kg; net force 3 N to the right; starts at rest; travels 4 m",
ha="center", fontsize=13)
fig.text(0.5, 0.795, r"$a=1.5$ m/s²; $t_f=\sqrt{16/3}\approx 2.309401$ s", ha="center")
blue, orange, green = "#2369a4", "#b85c17", "#34734b"
axes[0].plot(x, velocity, color=blue, lw=2.7)
axes[0].set(xlabel="Distance x (m)", ylabel="Rightward velocity v (m/s)",
xlim=(0, 4.2), ylim=(0, 4), xticks=[0, 1, 2, 3, 4])
axes[0].set_title(r"$v(x)=\sqrt{2Fx/m}$", pad=12)
axes[0].scatter([4], [velocity[-1]], color=blue, s=45, zorder=3)
axes[0].text(0.45, 3.6, "Final: 3.4641 m/s", color=blue, fontsize=11)
axes[1].plot(x, energy, color=orange, lw=2.7)
axes[1].set(xlabel="Distance x (m)", ylabel="Kinetic energy K (J)",
xlim=(0, 4.2), ylim=(0, 14), xticks=[0, 1, 2, 3, 4], yticks=[0, 4, 8, 12])
axes[1].set_title(r"$K(x)=Fx$", pad=12)
axes[1].scatter([4], [12], color=orange, s=45, zorder=3)
axes[1].text(0.45, 12.6, "Final: 12 J", color=orange, fontsize=11)
axes[2].plot(t, power, color=green, lw=2.7)
axes[2].fill_between(t, 0, power, color=green, alpha=0.16)
axes[2].axhline(mean_power, color="#74518e", lw=2, ls="--")
axes[2].set(xlabel="Time t (s)", ylabel="Power P (W)",
xlim=(0, final_time * 1.045), ylim=(0, 12), xticks=[0, 1, 2])
axes[2].set_title(r"$P(t)=Fat$", pad=12)
axes[2].scatter([final_time], [power[-1]], color=green, s=45, zorder=3)
axes[2].text(0.16, 10.8, "Final: 10.3923 W", color=green, fontsize=11)
axes[2].text(0.14, 5.6, "Mean: 5.19615 W", color="#74518e", fontsize=11,
bbox={"facecolor": "white", "edgecolor": "none", "pad": 2})
axes[2].text(1.28, 1.45, "Area: 12 J", color=green, fontsize=11)
for ax in axes:
ax.set_facecolor("white")
ax.grid(alpha=0.18)
ax.spines[["top", "right"]].set_visible(False)
fig.text(0.5, 0.045, "Velocity and energy use separate units. The mean-power line gives the same work over the same time.",
ha="center", fontsize=11)
fig.savefig("kinetic-energy-work-and-power.png", dpi=120,
facecolor="white", transparent=False)
plt.close(fig)
if __name__ == "__main__":
main()