codex/past-exam-of-the-short-options-course-of-the-university-of-oxford/short-options-2015-semicircular-extremals.py

past-exam-of-the-short-options-course-of-the-university-of-oxford/short-options-2015-semicircular-extremals.py
"""Generate the Question 6 illustration in the current working directory.

Tested with Python 3.14.4, matplotlib 3.10.7 and numpy 2.3.5.
"""

import matplotlib

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


def main():
    fig, axes = plt.subplots(1, 2, figsize=(9, 4.2), layout="constrained")
    fig.patch.set_facecolor("white")
    c, d = 0.65, 1.0
    for ax, free in zip(axes, (False, True)):
        h = 1.0 if free else d * d - c * c
        radius_squared = (1 + h) ** 2 + 4 * c * c
        radius = np.sqrt(radius_squared)
        theta = np.linspace(0, np.pi, 600)
        ax.plot(h + radius * np.cos(theta), radius * np.sin(theta),
                color="0.78", linewidth=1.2)
        x = np.linspace(-1, 1, 401)
        y = np.sqrt(radius_squared - (x - h) ** 2)
        ax.plot(x, y, color="#16648c", linewidth=3)
        ax.scatter([-1, 1], [y[0], y[-1]], color="#16648c", zorder=5)
        ax.plot([h, h], [0, radius], ":", color="0.5", linewidth=1)
        ax.scatter([h], [0], marker="x", color="#a14a22", zorder=6)
        ax.annotate("centre", (h, 0), xytext=(h + 0.08, 0.15), fontsize=9)
        ax.annotate("fixed height", (-1, y[0]), xytext=(-2.2, y[0] + 0.45),
                    arrowprops={"arrowstyle": "-", "color": "0.4"}, fontsize=9)
        if free:
            ax.plot([0.55, 1.45], [y[-1], y[-1]], color="#a14a22", linewidth=1.5)
            ax.annotate("free height: horizontal tangent", (1, y[-1]),
                        xytext=(-1.95, 3.05), fontsize=9,
                        arrowprops={"arrowstyle": "-", "color": "0.4"})
            title = "One endpoint height free"
            formula = r"$h=1,\quad R^2=4(1+c^2)$"
        else:
            ax.annotate("fixed height", (1, y[-1]), xytext=(1.2, y[-1] + 0.4),
                        arrowprops={"arrowstyle": "-", "color": "0.4"}, fontsize=9)
            title = "Both endpoint heights fixed"
            formula = r"$h=d^2-c^2$"
        ax.axhline(0, color="0.3", linewidth=0.8)
        ax.set(xlim=(-2.4, 3.1), ylim=(-0.25, 3.4), xlabel="$x$", ylabel="$y$",
               title=title + "\n" + formula)
        ax.set_aspect("equal", adjustable="box")
        ax.set_facecolor("white")
        ax.spines[["top", "right", "left", "bottom"]].set_visible(False)
        ax.set_xticks([-1, 0, 1, 2, 3])
        ax.set_yticks([0, 1, 2, 3])
    fig.savefig("short-options-2015-semicircular-extremals.png", dpi=140,
                facecolor="white", transparent=False,
                metadata={"Software": "codex-wiki matplotlib figure generator"})
    plt.close(fig)


if __name__ == "__main__":
    main()