{"spec_id":"energy-level-atomic","library":"plotly","language":"python","code":"\"\"\" anyplot.ai\nenergy-level-atomic: Atomic Energy Level Diagram\nLibrary: plotly 6.7.0 | Python 3.13.13\nQuality: 87/100 | Updated: 2026-05-30\n\"\"\"\n\nimport os\n\nimport plotly.graph_objects as go\n\n\n# Theme\nTHEME = os.getenv(\"ANYPLOT_THEME\", \"light\")\n\n# Theme-adaptive chrome (Imprint palette)\nPAGE_BG = \"#FAF8F1\" if THEME == \"light\" else \"#1A1A17\"\nELEVATED_BG = \"#FFFDF6\" if THEME == \"light\" else \"#242420\"\nINK = \"#1A1A17\" if THEME == \"light\" else \"#F0EFE8\"\nINK_SOFT = \"#4A4A44\" if THEME == \"light\" else \"#B8B7B0\"\nINK_MUTED = \"#6B6A63\" if THEME == \"light\" else \"#A8A79F\"\nGRID = \"rgba(26,26,23,0.15)\" if THEME == \"light\" else \"rgba(240,239,232,0.15)\"\n\n# Imprint palette — series colors grouped by spectral series\n# Lyman (UV): purple family for invisible ultraviolet\nlyman_colors = [\"#C475FD\", \"#954477\", \"#4467A3\"]\n# Balmer (visible): red/ochre/cyan/lime — physically motivated + clearly distinct\nbalmer_colors = [\"#AE3030\", \"#BD8233\", \"#2ABCCD\", \"#99B314\"]\n# Paschen (IR): green family — cool tones, no warm-hue overlap with Balmer\npaschen_colors = [\"#009E73\", \"#DDCC77\"]\n\n# Data — Hydrogen atom energy levels (E_n = -13.6/n² eV)\nquantum_numbers = [1, 2, 3, 4, 5, 6]\nenergies = {n: -13.6 / n**2 for n in quantum_numbers}\n\n# Transitions: (upper_n, lower_n, display_label, wavelength_nm)\nlyman_series = [(2, 1, \"Ly-α<br>121.6 nm\", 121.6), (3, 1, \"Ly-β<br>102.6 nm\", 102.6), (4, 1, \"Ly-γ<br>97.2 nm\", 97.2)]\nbalmer_series = [\n    (3, 2, \"Hα 656.3nm\", 656.3),\n    (4, 2, \"Hβ 486.1nm\", 486.1),\n    (5, 2, \"Hγ 434.0nm\", 434.0),\n    (6, 2, \"Hδ 410.2nm\", 410.2),\n]\npaschen_series = [(4, 3, \"Pa-α 1875nm\", 1875.1), (5, 3, \"Pa-β 1282nm\", 1281.8)]\n\nfig = go.Figure()\n\n# Energy level lines — use INK_SOFT for structural chrome\nline_left = 0.12\nline_right = 0.88\nfor n in quantum_numbers:\n    energy = energies[n]\n    fig.add_trace(\n        go.Scatter(\n            x=[line_left, line_right],\n            y=[energy, energy],\n            mode=\"lines\",\n            line={\"color\": INK_SOFT, \"width\": 3},\n            showlegend=False,\n            hovertemplate=f\"<b>n = {n}</b><br>E = {energy:.2f} eV<extra></extra>\",\n        )\n    )\n\n# Ionization limit — dashed muted line at 0 eV\nfig.add_trace(\n    go.Scatter(\n        x=[0.08, 0.92],\n        y=[0, 0],\n        mode=\"lines\",\n        line={\"color\": INK_MUTED, \"width\": 2, \"dash\": \"dash\"},\n        showlegend=False,\n        hovertemplate=\"<b>Ionization Limit</b><br>E = 0 eV  (n → ∞)<extra></extra>\",\n    )\n)\n\n# Quantum number labels — right side\n# n=1, n=2, n=3 are well-separated; individual labels are clean\nfor n in [1, 2, 3]:\n    fig.add_annotation(\n        x=line_right + 0.02,\n        y=energies[n],\n        text=f\"<b>n = {n}</b>\",\n        showarrow=False,\n        font={\"size\": 12, \"color\": INK_SOFT},\n        xanchor=\"left\",\n        yanchor=\"middle\",\n    )\n\n# n=4, 5, 6 converge tightly near 0 eV — single combined label above ionization limit\nfig.add_annotation(\n    x=line_right + 0.02,\n    y=0.45,\n    text=\"<b>n = 4, 5, 6</b>\",\n    showarrow=False,\n    font={\"size\": 11, \"color\": INK_SOFT},\n    xanchor=\"left\",\n    yanchor=\"bottom\",\n)\n\n# Left-side energy values for well-separated levels\nfor n in [1, 2, 3]:\n    fig.add_annotation(\n        x=line_left - 0.02,\n        y=energies[n],\n        text=f\"<b>{energies[n]:.2f}</b> eV\",\n        showarrow=False,\n        font={\"size\": 12, \"color\": INK_MUTED},\n        xanchor=\"right\",\n        yanchor=\"middle\",\n    )\n\n# Ionization label above the dashed line\nfig.add_annotation(\n    x=line_left - 0.02,\n    y=0,\n    text=\"<b>0</b> eV  <i>Ionization</i>\",\n    showarrow=False,\n    font={\"size\": 12, \"color\": INK_MUTED},\n    xanchor=\"right\",\n    yanchor=\"bottom\",\n    yshift=3,\n)\n\n# --- Lyman Series (UV) — left portion ---\nlyman_x = [0.21, 0.27, 0.33]\nfor i, (n_up, n_low, label, _wl) in enumerate(lyman_series):\n    e_up, e_low = energies[n_up], energies[n_low]\n    fig.add_annotation(\n        x=lyman_x[i],\n        y=e_low + 0.2,\n        ax=lyman_x[i],\n        ay=e_up - 0.2,\n        xref=\"x\",\n        yref=\"y\",\n        axref=\"x\",\n        ayref=\"y\",\n        showarrow=True,\n        arrowhead=2,\n        arrowsize=1.5,\n        arrowwidth=2.5,\n        arrowcolor=lyman_colors[i],\n        text=\"\",\n    )\n    fig.add_annotation(\n        x=lyman_x[i] - 0.015,\n        y=(e_up + e_low) / 2,\n        text=label,\n        showarrow=False,\n        font={\"size\": 11, \"color\": lyman_colors[i]},\n        xanchor=\"right\",\n    )\n\n# --- Balmer Series (Visible) — center portion ---\n# Labels staggered vertically across the n=2–n=4 range and alternated left/right\n# to prevent crowding (all four transitions end at n=2, so midpoints cluster)\nbalmer_x = [0.43, 0.49, 0.55, 0.61]\nbalmer_label_configs = [\n    (-0.012, \"right\", -1.65),  # Hα: left of arrow, upper\n    (0.012, \"left\", -2.25),  # Hβ: right of arrow, upper-mid\n    (-0.012, \"right\", -2.80),  # Hγ: left of arrow, lower-mid\n    (0.012, \"left\", -3.15),  # Hδ: right of arrow, lower\n]\nfor i, (n_up, n_low, label, _wl) in enumerate(balmer_series):\n    e_up, e_low = energies[n_up], energies[n_low]\n    xoff, xanc, ylbl = balmer_label_configs[i]\n    fig.add_annotation(\n        x=balmer_x[i],\n        y=e_low + 0.15,\n        ax=balmer_x[i],\n        ay=e_up - 0.15,\n        xref=\"x\",\n        yref=\"y\",\n        axref=\"x\",\n        ayref=\"y\",\n        showarrow=True,\n        arrowhead=2,\n        arrowsize=1.5,\n        arrowwidth=2.5,\n        arrowcolor=balmer_colors[i],\n        text=\"\",\n    )\n    fig.add_annotation(\n        x=balmer_x[i] + xoff,\n        y=ylbl,\n        text=label,\n        showarrow=False,\n        font={\"size\": 11, \"color\": balmer_colors[i]},\n        xanchor=xanc,\n    )\n\n# --- Paschen Series (Infrared) — right portion ---\n# Labels at transition midpoints, alternating sides to avoid overlap and the Balmer zone\npaschen_x = [0.73, 0.80]\n# Pa-α: label to LEFT of its arrow; Pa-β: label to RIGHT (x>0.85, clear of Balmer zone)\npaschen_label_configs = [\n    (0.70, \"right\"),  # Pa-α: left of arrow at 0.73\n    (0.88, \"right\"),  # Pa-β: right side (x>0.85), ending before n-label zone\n]\nfor i, (n_up, n_low, label, _wl) in enumerate(paschen_series):\n    e_up, e_low = energies[n_up], energies[n_low]\n    fig.add_annotation(\n        x=paschen_x[i],\n        y=e_low + 0.06,\n        ax=paschen_x[i],\n        ay=e_up - 0.06,\n        xref=\"x\",\n        yref=\"y\",\n        axref=\"x\",\n        ayref=\"y\",\n        showarrow=True,\n        arrowhead=2,\n        arrowsize=1.5,\n        arrowwidth=2.5,\n        arrowcolor=paschen_colors[i],\n        text=\"\",\n    )\n    lx, xanc = paschen_label_configs[i]\n    fig.add_annotation(\n        x=lx,\n        y=(e_up + e_low) / 2,\n        text=label,\n        showarrow=False,\n        font={\"size\": 11, \"color\": paschen_colors[i]},\n        xanchor=xanc,\n    )\n\n# Invisible hover targets at transition midpoints for HTML interactivity\nfor series, _colors, x_pos, name in [\n    (lyman_series, lyman_colors, lyman_x, \"Lyman\"),\n    (balmer_series, balmer_colors, balmer_x, \"Balmer\"),\n    (paschen_series, paschen_colors, paschen_x, \"Paschen\"),\n]:\n    hover_x, hover_y, hover_labels = [], [], []\n    for idx, (n_up, n_low, _lbl, wl) in enumerate(series):\n        e_up, e_low = energies[n_up], energies[n_low]\n        hover_x.append(x_pos[idx])\n        hover_y.append((e_up + e_low) / 2)\n        hover_labels.append(\n            f\"<b>{name} Series</b><br>n={n_up} → n={n_low}<br>λ = {wl} nm<br>ΔE = {abs(e_up - e_low):.2f} eV\"\n        )\n    fig.add_trace(\n        go.Scatter(\n            x=hover_x,\n            y=hover_y,\n            mode=\"markers\",\n            marker={\"size\": 30, \"opacity\": 0},\n            showlegend=False,\n            hovertext=hover_labels,\n            hoverinfo=\"text\",\n        )\n    )\n\n# Series group headers\nfig.add_annotation(\n    x=0.27,\n    y=1.6,\n    text=\"<b>Lyman</b><br><i>Ultraviolet</i>\",\n    showarrow=False,\n    font={\"size\": 13, \"color\": lyman_colors[0]},\n)\nfig.add_annotation(\n    x=0.52, y=1.6, text=\"<b>Balmer</b><br><i>Visible</i>\", showarrow=False, font={\"size\": 13, \"color\": balmer_colors[0]}\n)\nfig.add_annotation(\n    x=0.77,\n    y=1.6,\n    text=\"<b>Paschen</b><br><i>Infrared</i>\",\n    showarrow=False,\n    font={\"size\": 13, \"color\": paschen_colors[0]},\n)\n\n# Layout\nfig.update_layout(\n    autosize=False,\n    title={\n        \"text\": \"energy-level-atomic · python · plotly · anyplot.ai\",\n        \"font\": {\"size\": 16, \"color\": INK},\n        \"x\": 0.5,\n        \"xanchor\": \"center\",\n    },\n    xaxis={\"visible\": False, \"range\": [0, 1], \"fixedrange\": True},\n    yaxis={\n        \"title\": {\"text\": \"Energy (eV)\", \"font\": {\"size\": 12, \"color\": INK}},\n        \"tickfont\": {\"size\": 10, \"color\": INK_SOFT},\n        \"range\": [-15, 2.5],\n        \"zeroline\": False,\n        \"showgrid\": True,\n        \"gridcolor\": GRID,\n        \"gridwidth\": 1,\n        \"linecolor\": INK_SOFT,\n        \"zerolinecolor\": INK_SOFT,\n    },\n    paper_bgcolor=PAGE_BG,\n    plot_bgcolor=PAGE_BG,\n    font={\"color\": INK},\n    margin={\"l\": 120, \"r\": 140, \"t\": 80, \"b\": 60},\n    showlegend=False,\n)\n\n# Save — canonical 3200×1800 landscape canvas\nfig.write_image(f\"plot-{THEME}.png\", width=800, height=450, scale=4)\nfig.write_html(f\"plot-{THEME}.html\", include_plotlyjs=\"cdn\")\n"}