codexstellar-astrophysics-hr-diagram.py
stellar-astrophysics-hr-diagram.py
"""Schematic HR diagram; guide points are illustrative, not population data.
Run with ``make _media/stellar-astrophysics-hr-diagram.png``. Writes PNG to cwd.
Tested with Python 3.14.4, matplotlib 3.10.7 and numpy 2.3.5 (root pyproject.toml).
"""
from pathlib import Path
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
import numpy as np
fig, ax = plt.subplots(figsize=(7.0, 4.7), dpi=110, facecolor="white")
ax.set_facecolor("white")
temperature = np.geomspace(2400, 40000, 300)
for radius in (0.01, 1.0, 100.0):
ax.plot(temperature, radius**2 * (temperature / 5772.0)**4,
"--", color="#969eaa", lw=1.0, zorder=1)
# Chosen guides illustrate the region, rather than observations or model output.
main_t = [2800, 3500, 4500, 5772, 8000, 15000, 30000]
main_l = [0.001, 0.02, 0.2, 1, 15, 1000, 100000]
ax.plot(main_t, main_l, color="#246b9e", lw=10, alpha=0.15, solid_capstyle="round")
ax.plot(main_t, main_l, color="#246b9e", lw=1.8)
ax.text(9700, 0.7, "Main sequence\n(schematic)", color="#246b9e", fontsize=10, ha="center")
for t, lum, label, offset, color in [
(5772, 1.0, "Sun", (18, -17), "#ba7a00"),
(4000, 1000, "Cool giant\n(schematic)", (-112, 1), "#a14433"),
(20000, 0.01, "Hot white dwarf\n(schematic)", (8, 16), "#4b5a80"),
]:
ax.scatter([t], [lum], s=46, color=color, edgecolor="white", linewidth=0.7, zorder=4)
ax.annotate(label, (t, lum), textcoords="offset points", xytext=offset,
fontsize=9, color=color, arrowprops={"arrowstyle": "-", "color": color, "lw": 0.7})
for radius, t in [(0.01, 12000), (1.0, 14000), (100.0, 8000)]:
lum = radius**2 * (t / 5772.0)**4
ax.annotate(rf"$R={radius:g}R_\odot$", (t, lum), xytext=(0, 5),
textcoords="offset points", fontsize=9, color="#5e6672", ha="center")
ax.set_xscale("log")
ax.set_yscale("log")
ax.set_xlim(40000, 2400)
ax.set_ylim(1e-4, 2e5)
ax.set_xticks([30000, 15000, 8000, 5000, 3000], labels=["30,000", "15,000", "8,000", "5,000", "3,000"])
ax.minorticks_off()
ax.grid(axis="y", alpha=0.15)
ax.set_xlabel("Effective temperature (K): hotter to the left")
ax.set_ylabel(r"Luminosity ($L/L_\odot$)")
ax.set_title("A hot object can be faint if its radius is small", fontsize=12, pad=12)
fig.text(0.54, 0.012, r"Dashed: constant radius, $L/L_\odot=(R/R_\odot)^2(T/5772\,{\rm K})^4$",
ha="center", fontsize=9, color="#454b54")
fig.tight_layout(rect=(0, 0.04, 1, 1))
fig.savefig(Path.cwd() / "stellar-astrophysics-hr-diagram.png", facecolor="white")