codexpast-exam-of-the-mathematics-course-of-the-year-2-of-the-natural-sciences-course-of-the-university-of-cambridge2002paper-1-great-circle-route.py
past-exam-of-the-mathematics-course-of-the-year-2-of-the-natural-sciences-course-of-the-university-of-cambridge/2002/paper-1-great-circle-route.py
"""Original great-circle route plot; Python 3.14, NumPy 2.3, Matplotlib 3.10.
Uses the rounded exam coordinates, not modern city coordinates.
Run from the desired output directory; the PNG is written in the current directory.
"""
from pathlib import Path
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
import numpy as np
def main():
plt.rcParams.update({"font.size": 11, "figure.facecolor": "white", "axes.facecolor": "white"})
phi_a, phi_b = np.deg2rad([15, 105])
a = np.array([np.cos(phi_a), np.sin(phi_a), 1.0])/np.sqrt(2)
b = np.array([np.cos(phi_b), np.sin(phi_b), 0.0])
s = np.linspace(0, np.pi/2, 500)
points = np.cos(s)[:, None]*a + np.sin(s)[:, None]*b
lon = np.rad2deg(np.arctan2(points[:, 1], points[:, 0]))
lat = np.rad2deg(np.arcsin(points[:, 2]))
fig, ax = plt.subplots(figsize=(7.7, 4.4), dpi=120, layout="constrained")
ax.plot(lon, lat, color="#1674a5", lw=2.4, label=r"$\ell=\arctan[\cos(\phi-15^\circ)]$")
tick_s = np.linspace(0, np.pi/2, 7)
ticks = np.cos(tick_s)[:, None]*a + np.sin(tick_s)[:, None]*b
tick_lon = np.rad2deg(np.arctan2(ticks[:, 1], ticks[:, 0]))
tick_lat = np.rad2deg(np.arcsin(ticks[:, 2]))
ax.scatter(tick_lon, tick_lat, s=22, color="#1674a5", zorder=3)
ax.scatter([15, 105], [45, 0], color="#b35428", s=45, zorder=4)
ax.annotate("Rome (exam coordinates)", (15, 45), (21, 48), fontsize=10)
ax.annotate("Singapore\n(exam coordinates)", (105, 0), (73, 9), fontsize=10,
arrowprops={"arrowstyle": "->", "color": "0.3"})
ax.axhline(0, color="0.5", lw=0.8)
ax.set(xlim=(10, 110), ylim=(-3, 54), xlabel="Longitude east (degrees)",
ylabel="Latitude north (degrees)", title="A 90-degree great-circle arc")
ax.set_xticks(np.arange(15, 106, 15))
ax.set_yticks(np.arange(0, 46, 15))
ax.grid(alpha=0.2)
ax.legend(loc="lower left", fontsize=10)
ax.text(0.98, 0.95, "Dots are 15 degrees apart\nin spherical distance", ha="right", va="top",
transform=ax.transAxes, fontsize=10)
fig.savefig(Path(__file__).with_suffix(".png").name, facecolor="white", transparent=False)
plt.close(fig)
if __name__ == "__main__":
main()