{"spec_id":"line-tanabe-sugano","library":"seaborn","language":"python","code":"\"\"\" anyplot.ai\nline-tanabe-sugano: Tanabe-Sugano Diagram for Crystal Field Theory\nLibrary: seaborn 0.13.2 | Python 3.13.15\nQuality: 90/100 | Created: 2026-10-01\n\"\"\"\n\nimport os\n\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport pandas as pd\nimport seaborn as sns\n\n\n# Theme tokens (see prompts/default-style-guide.md \"Theme-adaptive Chrome\")\nTHEME = os.getenv(\"ANYPLOT_THEME\", \"light\")\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\"\n\n# Imprint palette — spin-allowed is position 1 (brand green), spin-forbidden position 2\nALLOWED = \"spin-allowed (quartet)\"\nFORBIDDEN = \"spin-forbidden (doublet)\"\nSPIN_COLORS = {ALLOWED: \"#009E73\", FORBIDDEN: \"#C475FD\"}\n\n# Data — d7 (Co2+) in an octahedral field: the Tanabe-Sugano matrices in the\n# strong-field basis, written in units of B with Dq/B on the diagonal\n# (Tanabe & Sugano, J. Phys. Soc. Jpn. 9, 753 (1954); C/B is their d7 value).\nC_OVER_B = 4.633\ndelta_over_b = np.linspace(0, 30, 301)\ndq = delta_over_b / 10  # Delta_o = 10 Dq\nsqrt2, sqrt3 = np.sqrt(2), np.sqrt(3)\n\nts_blocks = {\n    \"4T1\": ([2 * dq - 3, -8 * dq - 12], {(0, 1): 6}),\n    \"4T2\": ([2 * dq - 15], {}),\n    \"4A2\": ([12 * dq - 15], {}),\n    \"2A1\": ([2 * dq - 11 + 3 * C_OVER_B], {}),\n    \"2A2\": ([2 * dq + 9 + 3 * C_OVER_B], {}),\n    \"2E\": (\n        [12 * dq - 6 + 3 * C_OVER_B, 2 * dq + 8 + 6 * C_OVER_B, 2 * dq - 1 + 3 * C_OVER_B, -18 * dq - 8 + 4 * C_OVER_B],\n        {(0, 1): -6 * sqrt2, (0, 2): -3 * sqrt2, (1, 2): 10, (1, 3): sqrt3 * (2 + C_OVER_B), (2, 3): 2 * sqrt3},\n    ),\n    \"2T1\": (\n        [\n            12 * dq - 6 + 3 * C_OVER_B,\n            2 * dq + 3 * C_OVER_B,\n            2 * dq - 6 + 3 * C_OVER_B,\n            -8 * dq - 6 + 3 * C_OVER_B,\n            -8 * dq - 2 + 3 * C_OVER_B,\n        ],\n        {\n            (0, 1): -3,\n            (0, 2): 3,\n            (0, 4): -2 * sqrt3,\n            (1, 2): -3,\n            (1, 3): 3,\n            (1, 4): 3 * sqrt3,\n            (2, 3): -3,\n            (2, 4): -sqrt3,\n            (3, 4): 2 * sqrt3,\n        },\n    ),\n    \"2T2\": (\n        [\n            12 * dq + 5 * C_OVER_B,\n            2 * dq - 6 + 3 * C_OVER_B,\n            2 * dq + 4 + 3 * C_OVER_B,\n            -8 * dq + 6 + 5 * C_OVER_B,\n            -8 * dq - 2 + 3 * C_OVER_B,\n        ],\n        {\n            (0, 1): -3 * sqrt3,\n            (0, 2): -5 * sqrt3,\n            (0, 3): 4 + 2 * C_OVER_B,\n            (0, 4): 2,\n            (1, 2): 3,\n            (1, 3): -3 * sqrt3,\n            (1, 4): -3 * sqrt3,\n            (2, 3): -sqrt3,\n            (2, 4): sqrt3,\n            (3, 4): 10,\n        },\n    ),\n}\n\n# Diagonalize every symmetry block at each field strength (roots come out ascending,\n# so terms of the same symmetry and spin only ever approach, never cross)\nblock_roots = {}\nfor block, (diagonal, off_diagonal) in ts_blocks.items():\n    size = len(diagonal)\n    matrices = np.zeros((delta_over_b.size, size, size))\n    for i, element in enumerate(diagonal):\n        matrices[:, i, i] = element\n    for (i, j), element in off_diagonal.items():\n        matrices[:, i, j] = matrices[:, j, i] = element\n    block_roots[block] = np.linalg.eigvalsh(matrices)\n\n# Term symbol, its symmetry block, which root of that block, spin class\nterms = [\n    (r\"$^{4}T_{1g}(F)$\", \"4T1\", 0, ALLOWED),\n    (r\"$^{4}T_{2g}$\", \"4T2\", 0, ALLOWED),\n    (r\"$^{4}A_{2g}$\", \"4A2\", 0, ALLOWED),\n    (r\"$^{4}T_{1g}(P)$\", \"4T1\", 1, ALLOWED),\n    (r\"$^{2}E_{g}$\", \"2E\", 0, FORBIDDEN),\n    (r\"$^{2}T_{1g}$\", \"2T1\", 0, FORBIDDEN),\n    (r\"$^{2}T_{2g}$\", \"2T2\", 0, FORBIDDEN),\n    (r\"$^{2}A_{1g}$\", \"2A1\", 0, FORBIDDEN),\n    (r\"$^{2}A_{2g}$\", \"2A2\", 0, FORBIDDEN),\n]\n\n# Energies are measured from the ground term, which switches from the high-spin\n# 4T1g to the low-spin 2Eg at the crossover and kinks every curve there\nground_energy = np.min([block_roots[block][:, root] for _, block, root, _ in terms], axis=0)\ncurves = pd.concat(\n    [\n        pd.DataFrame(\n            {\n                \"delta_over_b\": delta_over_b,\n                \"energy_over_b\": block_roots[block][:, root] - ground_energy,\n                \"term\": term,\n                \"spin_class\": spin_class,\n            }\n        )\n        for term, block, root, spin_class in terms\n    ],\n    ignore_index=True,\n)\ncrossover = np.interp(0.0, block_roots[\"4T1\"][:, 0] - block_roots[\"2E\"][:, 0], delta_over_b)\n\n# Plot\nsns.set_theme(\n    style=\"ticks\",\n    rc={\n        \"figure.facecolor\": PAGE_BG,\n        \"axes.facecolor\": PAGE_BG,\n        \"axes.edgecolor\": INK_SOFT,\n        \"axes.labelcolor\": INK,\n        \"text.color\": INK,\n        \"xtick.color\": INK_SOFT,\n        \"ytick.color\": INK_SOFT,\n        \"grid.color\": INK,\n        \"grid.alpha\": 0.15,\n        \"legend.facecolor\": ELEVATED_BG,\n        \"legend.edgecolor\": INK_SOFT,\n    },\n)\nfig, ax = plt.subplots(figsize=(6, 6), dpi=400)\nsns.lineplot(\n    data=curves,\n    x=\"delta_over_b\",\n    y=\"energy_over_b\",\n    units=\"term\",\n    estimator=None,\n    hue=\"spin_class\",\n    style=\"spin_class\",\n    size=\"spin_class\",\n    hue_order=[ALLOWED, FORBIDDEN],\n    palette=SPIN_COLORS,\n    dashes={ALLOWED: \"\", FORBIDDEN: (4, 2)},\n    sizes={ALLOWED: 3.0, FORBIDDEN: 1.5},\n    ax=ax,\n)\n\n# High-spin / low-spin crossover\nax.axvline(crossover, color=INK_MUTED, linestyle=(0, (6, 4)), linewidth=1.6, zorder=0)\nax.text(\n    crossover - 0.8,\n    71,\n    f\"high-spin → low-spin\\n$\\\\Delta_o/B$ = {crossover:.1f}\",\n    ha=\"right\",\n    va=\"center\",\n    fontsize=8,\n    color=INK_MUTED,\n    linespacing=1.5,\n)\n\n# Term labels at the right edge, nudged apart where curves converge\nlabel_y = 0.0\nfor end_energy, term, spin_class in sorted(\n    (float(block_roots[block][-1, root] - ground_energy[-1]), term, spin_class)\n    for term, block, root, spin_class in terms\n):\n    label_y = max(end_energy, label_y + 2.6)\n    ax.text(\n        delta_over_b[-1] + 0.6, label_y, term, va=\"center\", fontsize=9, color=SPIN_COLORS[spin_class], clip_on=False\n    )\n\n# Style\nax.set_title(\n    \"Co$^{2+}$ d$^7$, C/B = 4.63 · line-tanabe-sugano · python · seaborn · anyplot.ai\",\n    fontsize=10,\n    fontweight=\"medium\",\n    color=INK,\n    pad=12,\n)\nax.set_xlabel(\"Ligand-field strength $\\\\Delta_o/B$\", fontsize=10)\nax.set_ylabel(\"Term energy above ground term $E/B$\", fontsize=10)\nax.set_xlim(0, 30)\nax.set_ylim(-1.6, 78)\nax.set_xticks(np.arange(0, 31, 5))\nax.set_yticks(np.arange(0, 78, 10))\nax.tick_params(axis=\"both\", labelsize=8, length=3)\nax.grid(True, alpha=0.15, linewidth=0.8)\nax.legend(*ax.get_legend_handles_labels(), title=None, fontsize=8, loc=\"upper left\", borderpad=0.8)\nsns.despine(ax=ax)\nfig.subplots_adjust(left=0.1, right=0.87, top=0.93, bottom=0.09)\n\n# Save\nplt.savefig(f\"plot-{THEME}.png\", dpi=400, facecolor=PAGE_BG)\n"}