codexpast-exam-of-the-mathematics-course-of-the-year-2-of-the-natural-sciences-course-of-the-university-of-cambridge2023paper-1-prolate-spheroid.py
past-exam-of-the-mathematics-course-of-the-year-2-of-the-natural-sciences-course-of-the-university-of-cambridge/2023/paper-1-prolate-spheroid.py
"""Q1 prolate spheroid; Python 3.14.4, root pyproject.toml dependencies.
Write the opaque PNG to cwd. Run in the matching _media course directory.
"""
from pathlib import Path
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
import numpy as np
def main():
a, c = np.sinh(1.0), np.cosh(1.0)
theta, phi = np.meshgrid(np.linspace(0, np.pi, 70), np.linspace(0, 2 * np.pi, 90))
x = a * np.sin(theta) * np.cos(phi)
y = a * np.sin(theta) * np.sin(phi)
z = c * np.cos(theta)
fig = plt.figure(figsize=(8.5, 4.4), facecolor="white")
ax = fig.add_subplot(1, 2, 1, projection="3d")
ax.plot_surface(x, y, z, color="#3f8db6", alpha=0.48, linewidth=0, antialiased=True)
ax.plot([0, 0], [0, 0], [-c, c], color="#444444", lw=1)
ax.scatter([0, 0], [0, 0], [-1, 1], color="#aa4a29", s=26, depthshade=False)
ax.set(xlabel=r"$x$", ylabel=r"$y$", zlabel=r"$z$", title=r"Surface $\xi=1$")
ax.set_box_aspect((a, a, c))
ax.view_init(elev=20, azim=-56)
ax.set_xticks([-1, 0, 1])
ax.set_yticks([-1, 0, 1])
ax.set_zticks([-1, 0, 1])
ax.tick_params(labelsize=8, pad=0)
meridian = fig.add_subplot(1, 2, 2)
angle = np.linspace(0, 2 * np.pi, 400)
meridian.plot(a * np.sin(angle), c * np.cos(angle), color="#175e90", lw=2)
meridian.axhline(0, color="#aaaaaa", lw=0.8)
meridian.axvline(0, color="#aaaaaa", lw=0.8)
meridian.scatter([0, 0], [-1, 1], color="#aa4a29", s=25, zorder=4)
meridian.plot([0, a], [0, 0], color="#175e90", lw=2.4)
meridian.plot([0, 0], [0, c], color="#4a7e39", lw=2.4)
meridian.annotate(r"$a=\sinh 1$", (a / 2, 0), xytext=(0.21, -0.32), fontsize=10)
meridian.annotate(r"$c=\cosh 1$", (0, c / 2), xytext=(0.22, 0.7), fontsize=10)
meridian.annotate("Foci", (0, -1), xytext=(0.28, -1.28), fontsize=10, color="#aa4a29", arrowprops={"arrowstyle": "->", "color": "#aa4a29"})
meridian.set(aspect="equal", xlim=(-1.48, 1.6), ylim=(-1.85, 1.85), xlabel=r"$x$ (section $y=0$)", ylabel=r"$z$", title="Meridian ellipse")
meridian.spines[["top", "right"]].set_visible(False)
meridian.grid(alpha=0.12)
fig.suptitle(r"$\dfrac{x^2+y^2}{\sinh^2 1}+\dfrac{z^2}{\cosh^2 1}=1$", fontsize=13, y=0.98)
fig.subplots_adjust(left=0.01, right=0.98, bottom=0.15, top=0.81, wspace=0.28)
fig.savefig(Path(__file__).with_suffix(".png").name, dpi=115, facecolor="white", transparent=False)
plt.close(fig)
if __name__ == "__main__":
main()