codex/tangent-normal-acceleration-on-parabola.py

tangent-normal-acceleration-on-parabola.py
"""Acceleration decomposition of r(t)=(t,t²) at t=1; PNG to CWD."""

from pathlib import Path

import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
import numpy as np


def main():
    point = np.array([1., 1.])
    velocity = np.array([1., 2.])
    acceleration = np.array([0., 2.])
    speed = np.linalg.norm(velocity)
    tangent = velocity / speed
    normal = np.array([-2., 1.]) / speed
    tangential = (acceleration @ tangent) * tangent
    normal_part = (acceleration @ normal) * normal
    curvature = 2 / (5*np.sqrt(5))
    assert np.allclose(tangential, [4/5, 8/5])
    assert np.allclose(normal_part, [-4/5, 2/5])
    assert np.allclose(tangential + normal_part, acceleration)
    assert np.isclose(acceleration @ tangent, 4/np.sqrt(5))
    assert np.isclose(acceleration @ normal, curvature*speed**2)
    fig, ax = plt.subplots(figsize=(8.6, 6.4), dpi=110)
    fig.patch.set_facecolor("white")
    x = np.linspace(-.8, 2.2, 251)
    ax.plot(x, x*x, color="#777777", lw=2, label=r"Path $r(t)=(t,t^2)$")
    ax.scatter(*point, color="#343434", s=45, zorder=5)
    for displacement, color in [(acceleration, "#343434"),
                                (tangential, "#245f9b"), (normal_part, "#c56521")]:
        ax.annotate("", point + displacement, point,
                    arrowprops=dict(arrowstyle="-|>", color=color,
                                    lw=2.5, mutation_scale=18))
    for end in [point+tangential, point+normal_part]:
        ax.plot([end[0], (point+acceleration)[0]],
                [end[1], (point+acceleration)[1]],
                color="#aaaaaa", ls="--", lw=1.3)
    ax.text(.62, .68, "P = (1, 1)", fontsize=11)
    ax.text(1.04, 3.12, "a = (0, 2)", fontsize=12)
    ax.text(1.88, 2.38, "Tangent part\n(0.8, 1.6)", fontsize=12,
            color="#245f9b")
    ax.text(-.61, 1.53, "Normal part\n(−0.8, 0.4)", fontsize=12,
            color="#c56521")
    ax.set_xlim(-1, 3.6)
    ax.set_ylim(-.2, 4.8)
    ax.set_aspect("equal")
    ax.set_xlabel("x")
    ax.set_ylabel("y")
    ax.set_title("Acceleration changes both speed and direction", fontsize=15)
    ax.grid(alpha=.16)
    ax.legend(loc="upper left", fontsize=10)
    fig.text(.5, .04,
             "At t = 1: tangential acceleration increases speed; "
             "normal acceleration turns the velocity. Dimensionless model.",
             ha="center", fontsize=10.5)
    fig.subplots_adjust(left=.07, right=.98, bottom=.14, top=.9)
    fig.savefig(Path.cwd() / "tangent-normal-acceleration-on-parabola.png",
                facecolor="white", transparent=False)
    plt.close(fig)


if __name__ == "__main__":
    main()