"""Plot exact cart kinematics while two balancing forces are switched off. Tested with Python 3.14, matplotlib 3.10.7 and numpy 2.3.5. Run from _media; writes inertial-cart-position-velocity-forces.png to CWD. """ from pathlib import Path import matplotlib.pyplot as plt import numpy as np def main(): plt.rcParams.update({"font.size": 11, "font.family": "DejaVu Sans"}) fig, axes = plt.subplots(3, 1, figsize=(9, 7.5), dpi=120, sharex=True, facecolor="white", gridspec_kw={"height_ratios": [1, 1, 1.35]}) time = np.linspace(0, 4, 401) axes[0].plot(time, 1.5 * time, color="#176a9b", linewidth=2.8) axes[0].set(ylabel="Position x (m)", ylim=(-0.4, 6.6), yticks=[0, 3, 6]) axes[0].text(0.12, 5, "x(t) = 1.5t", color="#176a9b") axes[1].plot(time, np.full_like(time, 1.5), color="#176a9b", linewidth=2.8) axes[1].set(ylabel="Velocity vₓ (m/s)", ylim=(-0.2, 2.2), yticks=[0, 1.5]) axes[1].text(0.12, 0.45, "vₓ(t) = +1.5 m/s throughout", color="#176a9b") force_ax = axes[2] for value, color, label in [(6, "#b3482f", "Rightward device"), (-6, "#725299", "Leftward device")]: force_ax.plot([0, 2], [value, value], color=color, linewidth=2.5, label=label) force_ax.plot(2, value, marker="o", markersize=7, markerfacecolor="white", markeredgecolor=color, markeredgewidth=1.8, zorder=5) force_ax.plot([2, 4], [0, 0], color=color, linewidth=2.5) force_ax.plot(time, np.zeros_like(time), color="#267b52", linestyle="--", linewidth=2, label="Net horizontal force", zorder=6) force_ax.plot(2, 0, "o", color="#267b52", markersize=7, zorder=7) force_ax.set(ylabel="Horizontal force (N)", xlabel="Time t (s)", ylim=(-8.5, 8.5), yticks=[-6, 0, 6], xlim=(0, 4), xticks=[0, 1, 2, 3, 4]) force_ax.legend(loc="lower right", fontsize=9, framealpha=1) for ax in axes: ax.axvspan(0, 2, color="#f2ede5", alpha=0.8, zorder=0) ax.axvline(2, color="#666666", linestyle=":", linewidth=1.3) ax.grid(axis="y", alpha=0.22) ax.spines[["top", "right"]].set_visible(False) axes[0].set_title("2 kg cart: both balancing horizontal forces switch off at t = 2 s", fontsize=14, pad=25) axes[0].text(1, 6.85, "Both devices on", ha="center", fontsize=10) axes[0].text(3, 6.85, "Both devices off; no impulse", ha="center", fontsize=10) fig.subplots_adjust(left=0.13, right=0.97, top=0.87, bottom=0.1, hspace=0.2) fig.text(0.5, 0.025, "Exact model curves, not measured data. Vertical forces remain balanced.", ha="center", fontsize=10) fig.savefig(Path.cwd() / "inertial-cart-position-velocity-forces.png", facecolor="white") plt.close(fig) if __name__ == "__main__": main()