codexisotope-nucleus-neon-neutron-counts.py
isotope-nucleus-neon-neutron-counts.py
"""Render a counting diagram; Python 3.14, matplotlib 3.10.7, numpy 2.3.5.
Run from _media; the matching PNG is written to the current directory.
Dots are inventory tokens, not positions or a nuclear structure model.
"""
from pathlib import Path
import matplotlib.pyplot as plt
from matplotlib.patches import Circle, FancyBboxPatch
def main():
fig, axes = plt.subplots(1, 3, figsize=(9.6, 4.2), dpi=110, facecolor="white")
fig.suptitle("Neon isotopes: ten protons, different neutron counts", fontsize=16, y=0.96)
for ax, mass_number in zip(axes, (20, 21, 22), strict=True):
neutron_number = mass_number - 10
assert 10 + neutron_number == mass_number
ax.set(xlim=(-0.5, 4.5), ylim=(-1.0, 6.6), aspect="equal")
ax.axis("off")
ax.add_patch(FancyBboxPatch((-0.4, -0.85), 4.8, 7.20,
boxstyle="round,pad=0.02", facecolor="white",
edgecolor="#a9b4bf", linewidth=1.3))
ax.text(2, 5.55, rf"${{}}^{{{mass_number}}}_{{10}}\mathrm{{Ne}}$", ha="center", fontsize=21)
ax.text(2, 4.85, "10 protons", ha="center", color="#165c9e", fontsize=12)
for k in range(10):
ax.add_patch(Circle((k % 5, 4.25 - 0.55 * (k // 5)), 0.19,
facecolor="#2378b8", edgecolor="#165c9e"))
ax.text(2, 2.95, f"{neutron_number} neutrons", ha="center", color="#5b626b", fontsize=12)
for k in range(neutron_number):
ax.add_patch(Circle((k % 5, 2.35 - 0.55 * (k // 5)), 0.19,
facecolor="#9ca7b1", edgecolor="#5b626b"))
ax.text(2, 0.30, f"A = 10 + {neutron_number} = {mass_number}", ha="center", fontsize=12)
ax.text(2, -0.25, "Z = 10 in every nucleus", ha="center", fontsize=10)
fig.text(0.5, 0.075, "One dot = one nucleon. Layout is an inventory, not a spatial model.",
ha="center", fontsize=11)
fig.text(0.5, 0.026, "Electron removal changes ion charge; it does not change any of these nuclei.",
ha="center", fontsize=11)
fig.subplots_adjust(left=0.025, right=0.975, top=0.84, bottom=0.16, wspace=0.1)
fig.savefig(Path.cwd() / (Path(__file__).stem + ".png"), facecolor="white", transparent=False)
plt.close(fig)
if __name__ == "__main__":
main()