codexzeeman-viewing-direction-polarization.py
zeeman-viewing-direction-polarization.py
"""Project ideal Zeeman dipoles; Python 3.14, matplotlib 3.10.7, numpy 2.3.5.
Run from _media. Traces and angular factors are calculated, not measured.
"""
from pathlib import Path
import matplotlib.pyplot as plt
import numpy as np
def main():
plt.rcParams.update({"font.size": 12, "font.family": "DejaVu Sans"})
fig = plt.figure(figsize=(10.8, 7.2), facecolor="white")
gs = fig.add_gridspec(2, 2, height_ratios=[1, 1.1], hspace=0.62, wspace=0.3)
side = fig.add_subplot(gs[0, 0])
axial = fig.add_subplot(gs[0, 1])
angular = fig.add_subplot(gs[1, :])
green, blue = "#21754c", "#235fb0"
fig.suptitle("The same transitions look different from different directions", fontsize=17, y=0.97)
for ax in [side, axial]:
ax.set(xlim=(-2.5, 2.5), ylim=(-1.45, 1.45), aspect="equal")
ax.axis("off")
side.set_title(r"Across $\mathbf{B}$: three frequencies", fontsize=13)
side.annotate("", xy=(-2.1, 1.0), xytext=(-2.1, -0.7),
arrowprops={"arrowstyle": "->", "lw": 2, "color": "#333333"})
side.text(-2.1, -1.0, r"$\mathbf{B}$", ha="center")
side.annotate("", xy=(-0.6, 0.8), xytext=(-0.6, -0.8),
arrowprops={"arrowstyle": "<->", "lw": 3, "color": green})
side.text(-0.6, -1.2, r"$\pi$: $\mathbf{E}\parallel\mathbf{B}$", ha="center", color=green)
side.annotate("", xy=(1.9, 0), xytext=(0.4, 0),
arrowprops={"arrowstyle": "<->", "lw": 3, "color": blue})
side.text(1.15, -1.2, r"$\sigma^\pm$: $\mathbf{E}\perp\mathbf{B}$", ha="center", color=blue)
axial.set_title(r"Along $\mathbf{B}$: two frequencies", fontsize=13)
axial.text(-2.0, 0.1, r"$\odot$", ha="center", fontsize=28)
axial.text(-2.0, -0.6, r"$\mathbf{B}$", ha="center")
t = np.linspace(0, 2 * np.pi, 241)
for center, rotation, label in [(-0.6, 1, r"$\sigma^-$"), (1.3, -1, r"$\sigma^+$")]:
axial.plot(center + 0.57 * np.cos(t), 0.57 * np.sin(t), color=blue, lw=2)
a, b = 0.25, 0.25 + rotation * 0.65
axial.annotate("", xy=(center + 0.57 * np.cos(b), 0.57 * np.sin(b)),
xytext=(center + 0.57 * np.cos(a), 0.57 * np.sin(a)),
arrowprops={"arrowstyle": "-|>", "lw": 2, "color": blue})
axial.text(center, -0.92, label, ha="center", color=blue)
axial.text(0.3, -1.4, r"$\pi$ absent; opposite rotations (convention dependent)", ha="center", fontsize=10)
degrees = np.linspace(0, 90, 361)
theta = np.deg2rad(degrees)
angular.plot(degrees, np.sin(theta) ** 2, color=green, lw=2.5,
label=r"$\pi$: $\sin^2\theta$")
angular.plot(degrees, (1 + np.cos(theta) ** 2) / 2, color=blue, lw=2.5,
label=r"Each $\sigma$: $(1+\cos^2\theta)/2$")
angular.set(xlim=(0, 90), ylim=(0, 1.08), xticks=[0, 30, 60, 90],
xlabel=r"Viewing angle $\theta$ from the magnetic field (degrees)",
ylabel="Angular intensity factor")
angular.grid(alpha=0.18)
angular.spines[["top", "right"]].set_visible(False)
angular.legend(loc="center right", frameon=True, facecolor="white", framealpha=1)
fig.text(0.5, 0.025, "Calculated for equal dipole magnitudes • state populations and transition strengths are separate",
ha="center", fontsize=11, color="#444444")
fig.subplots_adjust(left=0.105, right=0.96, bottom=0.13, top=0.85)
fig.savefig(Path(__file__).stem + ".png", dpi=100, facecolor="white")
plt.close(fig)
if __name__ == "__main__":
main()