codexcoriolis-free-ball-two-frames.py
coriolis-free-ball-two-frames.py
"""Plot one force-free horizontal motion in fixed and rotating coordinates.
Run from the desired output directory. Tested with Python 3.14,
Matplotlib 3.10.7 and NumPy 2.3.5; dependencies are in pyproject.toml.
"""
from pathlib import Path
import matplotlib.pyplot as plt
import numpy as np
def main():
omega, speed = 0.8, 0.25
time = np.linspace(0, 3, 601)
radius = speed * time
fig, axes = plt.subplots(1, 2, figsize=(10, 5.4), facecolor="white")
fig.subplots_adjust(left=0.07, right=0.98, bottom=0.19, top=0.81, wspace=0.25)
colors = ["#222222", "#0072b2", "#d55e00", "#7b3294"]
for ax, title, rotating in zip(
axes, ["Laboratory: straight path", "Rotating axes: curved path"], [False, True]
):
ax.set_facecolor("white")
ax.set_aspect("equal")
ax.set_xlim(-0.85, 0.85)
ax.set_ylim(-0.82, 0.43)
for r in (0.25, 0.50, 0.75):
ax.add_patch(plt.Circle((0, 0), r, fill=False, color="#dddddd", lw=0.8))
ax.axhline(0, color="#bbbbbb", lw=0.8)
ax.axvline(0, color="#bbbbbb", lw=0.8)
x = radius * np.cos(omega * time) if rotating else radius
y = -radius * np.sin(omega * time) if rotating else np.zeros_like(time)
ax.plot(x, y, color="#225577", lw=2.5)
for t, color in zip(range(4), colors):
px = speed * t * np.cos(omega * t) if rotating else speed * t
py = -speed * t * np.sin(omega * t) if rotating else 0
ax.plot(px, py, "o", color=color, ms=6)
offset = (7, 10) if t != 3 else ((-8, -20) if not rotating else (-13, 12))
ax.annotate(f"{t} s", (px, py), xytext=offset, textcoords="offset points",
fontsize=10, color=color, ha="left" if t != 3 else "right")
ax.set_title(title, fontsize=13, pad=12)
ax.set_xlabel(r"$x_{\rm rot}$ (m)" if rotating else r"$x_{\rm lab}$ (m)", fontsize=11)
ax.set_ylabel(r"$y_{\rm rot}$ (m)" if rotating else r"$y_{\rm lab}$ (m)", fontsize=11)
ax.set_xticks([-0.75, -0.5, -0.25, 0, 0.25, 0.5, 0.75])
ax.tick_params(labelsize=9)
fig.suptitle("One free ball, two reference frames", fontsize=17, y=0.98)
fig.text(0.5, 0.885, r"$u=0.25\ {\rm m\,s^{-1}},\quad \Omega=0.8\ {\rm rad\,s^{-1}}$ counterclockwise; equal scales",
ha="center", fontsize=11)
fig.text(0.5, 0.073, "Matching dots mark the same events. No horizontal force acts in the laboratory.",
ha="center", fontsize=11)
fig.text(0.5, 0.026, "Full rotating acceleration = Coriolis acceleration + centrifugal acceleration.",
ha="center", fontsize=11, color="#333333")
fig.savefig(Path.cwd() / (Path(__file__).stem + ".png"), dpi=110, facecolor="white")
plt.close(fig)
if __name__ == "__main__":
main()