{"spec_id":"line-tanabe-sugano","library":"ggplot2","language":"r","code":"#' anyplot.ai\n#' line-tanabe-sugano: Tanabe-Sugano Diagram for Crystal Field Theory\n#' Library: ggplot2 3.5.1 | R 4.4.1\n#' Quality: 91/100 | Created: 2026-10-01\n\nlibrary(ggplot2)\nlibrary(dplyr)\nlibrary(tidyr)\nlibrary(scales)\nlibrary(ragg)\n\n# --- Theme tokens -----------------------------------------------------------\nTHEME    <- Sys.getenv(\"ANYPLOT_THEME\", \"light\")\nPAGE_BG  <- if (THEME == \"light\") \"#FAF8F1\" else \"#1A1A17\"\nINK      <- if (THEME == \"light\") \"#1A1A17\" else \"#F0EFE8\"\nINK_SOFT <- if (THEME == \"light\") \"#4A4A44\" else \"#B8B7B0\"\n\n# Imprint palette: position 1 (brand green) carries the spin-allowed terms,\n# position 2 (lavender) the spin-forbidden ones.\nSPIN_ALLOWED   <- \"#009E73\"\nSPIN_FORBIDDEN <- \"#C475FD\"\nALLOWED_LABEL   <- \"Spin-allowed (triplet)\"\nFORBIDDEN_LABEL <- \"Spin-forbidden (singlet)\"\n\n# --- Data: octahedral d2 term energies (V3+, C/B = 4.42) --------------------\n# Energies are in units of the Racah parameter B, the centroid A dropped. A\n# term symbol that occurs in two strong-field configurations gets a 2x2\n# secular block whose off-diagonal element mixes them; both roots of the block\n# are real term energies, and because the mixing never vanishes the two roots\n# approach without crossing.\nC_B <- 4.42\nfield_strength <- seq(0, 40, length.out = 321)\n\nblocks <- tibble::tribble(\n    ~lower_term, ~upper_term, ~e11,         ~e22_0,      ~e22_slope, ~e12,\n    \"3T1g(F)\",   \"3T1g(P)\",   -5,           4,           1,          6,\n    \"1T2g(D)\",   \"1T2g(G)\",   1 + 2 * C_B,  2 * C_B,     1,          2 * sqrt(3),\n    \"1Eg(D)\",    \"1Eg(G)\",    1 + 2 * C_B,  2 * C_B,     2,          2 * sqrt(3),\n    \"1A1g(G)\",   \"1A1g(S)\",   10 + 5 * C_B, 8 + 4 * C_B, 2,          sqrt(6) * (2 + C_B)\n)\n\nroots <- expand_grid(blocks, delta_over_b = field_strength) |>\n    mutate(\n        e22    = e22_0 + e22_slope * delta_over_b,\n        centre = (e11 + e22) / 2,\n        split  = sqrt(((e11 - e22) / 2)^2 + e12^2)\n    )\n\n# Terms carried by a single strong-field configuration need no block — their\n# energy is linear in the field strength.\nsingles <- expand_grid(\n    tibble::tribble(\n        ~term,     ~e0,         ~slope,\n        \"3T2g\",    -8,          1,\n        \"3A2g\",    -8,          2,\n        \"1T1g(G)\", 4 + 2 * C_B, 1\n    ),\n    delta_over_b = field_strength\n)\n\nterms <- bind_rows(\n    transmute(roots, delta_over_b, term = lower_term, energy = centre - split),\n    transmute(roots, delta_over_b, term = upper_term, energy = centre + split),\n    transmute(singles, delta_over_b, term, energy = e0 + slope * delta_over_b)\n) |>\n    group_by(delta_over_b) |>\n    mutate(energy_over_b = energy - energy[term == \"3T1g(F)\"]) |>\n    ungroup() |>\n    filter(!term %in% c(\"1Eg(G)\", \"1A1g(S)\")) |>\n    mutate(spin = if_else(startsWith(term, \"3\"), ALLOWED_LABEL, FORBIDDEN_LABEL))\n\n# Term symbols as plotmath, so the multiplicity is a true superscript and the\n# Mulliken index and the g parity are true subscripts.\nTERM_SYMBOLS <- c(\n    \"3T1g(F)\" = \"''^3*T[1*g]*'(F)'\",\n    \"3T1g(P)\" = \"''^3*T[1*g]*'(P)'\",\n    \"3T2g\"    = \"''^3*T[2*g]\",\n    \"3A2g\"    = \"''^3*A[2*g]\",\n    \"1A1g(G)\" = \"''^1*A[1*g]*'(G)'\",\n    \"1Eg(D)\"  = \"''^1*E[g]*'(D)'\",\n    \"1T1g(G)\" = \"''^1*T[1*g]*'(G)'\",\n    \"1T2g(D)\" = \"''^1*T[2*g]*'(D)'\",\n    \"1T2g(G)\" = \"''^1*T[2*g]*'(G)'\"\n)\n\n# The two 1D-derived terms converge onto the same t2g^2 pair at strong field,\n# so their labels are pulled apart in their own order to stay readable.\ncurve_labels <- terms |>\n    filter(delta_over_b == max(delta_over_b)) |>\n    mutate(\n        symbol  = TERM_SYMBOLS[term],\n        label_y = energy_over_b + case_when(\n            term == \"1Eg(D)\" ~ 2.7,\n            term == \"1T2g(D)\" ~ -2.7,\n            term == \"3T2g\" ~ 1.4,\n            term == \"1A1g(G)\" ~ -1.4,\n            term == \"1T1g(G)\" ~ 1.15,\n            term == \"1T2g(G)\" ~ -1.15,\n            term == \"3T1g(P)\" ~ -0.8,\n            .default = 0\n        )\n    )\n\n# --- Plot -------------------------------------------------------------------\np <- ggplot(terms, aes(delta_over_b, energy_over_b, group = term,\n                       color = spin, linetype = spin, linewidth = spin)) +\n    geom_line(lineend = \"round\") +\n    geom_text(\n        data = curve_labels,\n        aes(x = delta_over_b + 0.7, y = label_y, label = symbol, color = spin),\n        parse = TRUE, hjust = 0, size = 4.1,\n        inherit.aes = FALSE, show.legend = FALSE\n    ) +\n    scale_color_manual(values = c(SPIN_ALLOWED, SPIN_FORBIDDEN) |>\n                           setNames(c(ALLOWED_LABEL, FORBIDDEN_LABEL))) +\n    scale_linetype_manual(values = c(\"solid\", \"longdash\") |>\n                              setNames(c(ALLOWED_LABEL, FORBIDDEN_LABEL))) +\n    scale_linewidth_manual(values = c(1.4, 0.8) |>\n                               setNames(c(ALLOWED_LABEL, FORBIDDEN_LABEL))) +\n    scale_x_continuous(breaks = seq(0, 40, 5), expand = expansion(mult = 0)) +\n    scale_y_continuous(breaks = seq(0, 80, 10), expand = expansion(mult = 0.015)) +\n    coord_cartesian(xlim = c(0, 40), ylim = c(0, 80), clip = \"off\") +\n    labs(\n        title    = \"line-tanabe-sugano · r · ggplot2 · anyplot.ai\",\n        subtitle = expression(d^2 * \" octahedral field, V\"^\"3+\" * \", C/B = 4.42\"),\n        x        = expression(\"Ligand-field strength \" * Delta[~o] * \"/B\"),\n        y        = expression(\"Term energy E/B\")\n    ) +\n    theme_minimal(base_size = 8) +\n    theme(\n        plot.background   = element_rect(fill = PAGE_BG, color = PAGE_BG),\n        panel.background  = element_rect(fill = PAGE_BG, color = NA),\n        panel.grid.major  = element_line(color = alpha(INK, 0.15), linewidth = 0.25),\n        panel.grid.minor  = element_blank(),\n        axis.line         = element_line(color = INK_SOFT, linewidth = 0.35),\n        axis.ticks        = element_blank(),\n        axis.title        = element_text(color = INK, size = 10),\n        axis.title.x      = element_text(margin = margin(t = 6)),\n        axis.text         = element_text(color = INK_SOFT, size = 8),\n        plot.title        = element_text(color = INK, size = 12, face = \"bold\"),\n        plot.subtitle     = element_text(color = INK_SOFT, size = 9,\n                                         margin = margin(b = 10)),\n        legend.position   = \"bottom\",\n        legend.title      = element_blank(),\n        legend.text       = element_text(color = INK_SOFT, size = 8),\n        legend.key        = element_blank(),\n        legend.key.width  = unit(0.55, \"cm\"),\n        legend.background = element_blank(),\n        legend.box.spacing = unit(0.25, \"cm\"),\n        plot.margin       = margin(t = 10, r = 62, b = 6, l = 8)\n    )\n\n# --- Save -------------------------------------------------------------------\nggsave(\n    filename = sprintf(\"plot-%s.png\", THEME),\n    plot     = p,\n    device   = ragg::agg_png,\n    width    = 6,\n    height   = 6,\n    units    = \"in\",\n    dpi      = 400,\n    bg       = PAGE_BG\n)\n"}