codexpast-exam-of-the-short-options-course-of-the-university-of-oxfordshort-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()