codex/wien-wavelength-temperature-peaks.py

wien-wavelength-temperature-peaks.py
"""Plot ideal wavelength peaks; Python 3.14, NumPy 2.3.5, Matplotlib 3.10.7.

Run from _media: MPLBACKEND=Agg python ../wien-wavelength-temperature-peaks.py
"""
from pathlib import Path
import numpy as np
import matplotlib.pyplot as plt

H = 6.62607015e-34
C = 299792458.0
K = 1.380649e-23
X = 4.965114231744276
B = H * C / (K * X)


def normalized_spectrum(wavelength, temperature):
    x = H * C / (wavelength * K * temperature)
    return (x / X) ** 5 * np.expm1(X) / np.expm1(np.minimum(x, 700))


def main():
    plt.rcParams.update({'font.size': 11, 'axes.spines.top': False,
                         'axes.spines.right': False, 'figure.facecolor': 'white'})
    fig, (left, right) = plt.subplots(1, 2, figsize=(10.4, 4.2), layout='constrained')
    wavelength = np.geomspace(0.15, 80, 1600)
    temperatures = [300, 1000, 5000]
    colors = ['#197686', '#b55a16', '#7143a3']
    for temperature, color in zip(temperatures, colors):
        peak = B / temperature * 1e6
        left.plot(wavelength, normalized_spectrum(wavelength * 1e-6, temperature),
                  color=color, label=f'{temperature} K: {peak:.3f} μm', lw=2)
        left.plot(peak, 1, 'o', color=color)
        right.plot(temperature, peak, 'o', color=color, zorder=4)
        right.annotate(f'{temperature} K\n{peak:.3f} μm', (temperature, peak),
                       xytext=(8, 5), textcoords='offset points', fontsize=10)
    left.set(xscale='log', xlim=(0.15, 80), ylim=(0, 1.42),
             xlabel='Wavelength λ (μm)', ylabel='Bλ / its own peak value',
             title='The shape shifts as temperature changes')
    left.legend(loc='upper right', fontsize=9, frameon=False)
    t = np.geomspace(150, 12000, 400)
    right.plot(t, B / t * 1e6, color='#34495e', lw=2)
    right.set(xscale='log', yscale='log', xlim=(150, 12000), ylim=(0.18, 25),
              xlabel='Temperature T (K)', ylabel='Wavelength peak λmax (μm)',
              title='λmax T = 2897.772 μm K')
    for ax in (left, right):
        ax.grid(alpha=0.18, which='both')
    fig.savefig(Path(__file__).stem + '.png', dpi=130, facecolor='white')
    plt.close(fig)


if __name__ == '__main__':
    main()