codex/past-exam-of-the-physics-course-of-the-year-1-of-the-natural-sciences-course-of-the-university-of-cambridge/2022-q4-lens-rays.py

past-exam-of-the-physics-course-of-the-year-1-of-the-natural-sciences-course-of-the-university-of-cambridge/2022-q4-lens-rays.py
"""Original ideal thin-lens construction. Python 3.14.4; root pyproject.toml deps.

Run from the desired output directory; writes the PNG basename into cwd.
"""
from pathlib import Path

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


def main():
    fig, ax = plt.subplots(figsize=(9.2, 4.8), layout="constrained")
    fig.patch.set_facecolor("white")
    ax.set_facecolor("white")
    ax.axhline(0, color="0.45", lw=1)
    ax.annotate("", (0, 9), (0, -12), arrowprops={"arrowstyle": "<->", "lw": 2, "color": "#506882"})
    ax.text(0.6, 8, "Converging lens", color="#506882")
    for x, text in [(-8, "$F$"), (8, "$F'$ (8 cm)")]:
        ax.plot(x, 0, "ko", ms=4)
        ax.text(x, 0.6, text, ha="center")
    ax.annotate("", (-12, 5), (-12, 0), arrowprops={"arrowstyle": "-|>", "lw": 2.8, "color": "#28794c"})
    ax.text(-12, 5.7, "Object\n5 cm", ha="center", color="#28794c")
    ax.annotate("", (24, -10), (24, 0), arrowprops={"arrowstyle": "-|>", "lw": 2.8, "color": "#28794c"})
    ax.text(24.7, -8.8, "Real image\n10 cm, inverted", color="#28794c")
    paths = [([-12, 0, 24], [5, 5, -10], "#c06a13"), ([-12, 0, 24], [5, 0, -10], "#406bb4")]
    for xs, ys, color in paths:
        ax.plot(xs, ys, color=color, lw=1.8)
        for a, b in [(0, 1), (1, 2)]:
            dx, dy = xs[b] - xs[a], ys[b] - ys[a]
            start = (xs[a] + 0.45 * dx, ys[a] + 0.45 * dy)
            end = (xs[a] + 0.57 * dx, ys[a] + 0.57 * dy)
            ax.annotate("", end, start, arrowprops={"arrowstyle": "-|>", "color": color, "lw": 1.5})
    for xa, xb, y, label in [(-12, 0, -12, "$u=12$ cm"), (0, 24, -14, "$v=24$ cm")]:
        ax.annotate("", (xb, y), (xa, y), arrowprops={"arrowstyle": "<->", "lw": 1, "color": "0.3"})
        ax.text((xa + xb) / 2, y - 0.65, label, ha="center", va="top")
    ax.set(xlim=(-16, 36), ylim=(-16, 10), xlabel="$x$ (cm)", ylabel="Height (cm)", title="Thin-lens construction: two independent rays meet at (24, −10) cm")
    ax.set_aspect("equal", adjustable="box")
    ax.spines[["top", "right"]].set_visible(False)
    fig.savefig(Path(__file__).with_suffix(".png").name, dpi=150, facecolor="white")
    plt.close(fig)


if __name__ == "__main__":
    main()