{"spec_id":"line-arrhenius","library":"plotnine","language":"python","code":"\"\"\" anyplot.ai\nline-arrhenius: Arrhenius Plot for Reaction Kinetics\nLibrary: plotnine 0.15.7 | Python 3.13.14\nQuality: 91/100 | Updated: 2026-06-24\n\"\"\"\n\nimport os\n\nimport numpy as np\nimport pandas as pd\nfrom plotnine import (\n    aes,\n    annotate,\n    element_blank,\n    element_line,\n    element_rect,\n    element_text,\n    geom_line,\n    geom_point,\n    geom_ribbon,\n    ggplot,\n    labs,\n    scale_x_continuous,\n    scale_y_continuous,\n    theme,\n    theme_minimal,\n)\nfrom scipy.stats import t as t_dist\n\n\n# Theme tokens\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 — first series always #009E73, position 3 for fit line\nBRAND = \"#009E73\"\nBLUE = \"#4467A3\"\n\n# Data — first-order decomposition, 300–600 K with realistic experimental scatter\ntemperature_K = np.array([300, 350, 400, 450, 500, 550, 600])\nnoise = np.array([0.22, -0.18, 0.25, -0.14, 0.19, -0.21, 0.15])\nrate_constant_k = np.exp(-4878.0 / temperature_K + 9.5 + noise)\n\ninv_T = 1.0 / temperature_K\nln_k = np.log(rate_constant_k)\n\n# Regression statistics\ncoeffs = np.polyfit(inv_T, ln_k, 1)\nslope, intercept = coeffs\nln_k_pred = np.polyval(coeffs, inv_T)\nss_res = np.sum((ln_k - ln_k_pred) ** 2)\nss_tot = np.sum((ln_k - ln_k.mean()) ** 2)\nr_squared = 1 - ss_res / ss_tot\n\nR_gas = 8.314\nEa_kJ = -slope * R_gas / 1000\n\ndf = pd.DataFrame({\"inv_T\": inv_T, \"ln_k\": ln_k})\n\n# Regression line with 95% confidence band\ninv_T_fine = np.linspace(inv_T.min(), inv_T.max(), 200)\nln_k_fit = np.polyval(coeffs, inv_T_fine)\n\nn = len(inv_T)\nse_residual = np.sqrt(ss_res / (n - 2))\ninv_T_mean = inv_T.mean()\ninv_T_ss = np.sum((inv_T - inv_T_mean) ** 2)\nse_fit = se_residual * np.sqrt(1.0 / n + (inv_T_fine - inv_T_mean) ** 2 / inv_T_ss)\nt_val = t_dist.ppf(0.975, n - 2)\nci_lower = ln_k_fit - t_val * se_fit\nci_upper = ln_k_fit + t_val * se_fit\n\ndf_fit = pd.DataFrame({\"inv_T\": inv_T_fine, \"ln_k_fit\": ln_k_fit, \"ci_lower\": ci_lower, \"ci_upper\": ci_upper})\n\n# X-axis ticks with dual annotation (1/T + temperature in K)\ntick_temps = [300, 400, 500, 600]\ntick_positions = [1.0 / t for t in tick_temps]\ntick_labels = [f\"{1.0 / t:.2e}\\n({t} K)\" for t in tick_temps]\n\n# Annotation placement — upper-left quadrant\nanno_x = inv_T.min() + 0.35 * (inv_T.max() - inv_T.min())\nanno_y_top = ln_k.max() - 0.2\n\nanno_r2 = f\"R² = {r_squared:.4f}\"\nanno_ea = f\"Eₐ = {Ea_kJ:.1f} kJ/mol\"\nanno_slope = f\"slope = −Eₐ/R = {slope:.0f} K\"\n\ntitle = \"line-arrhenius · python · plotnine · anyplot.ai\"\n\n# Plot\nplot = (\n    ggplot(df, aes(x=\"inv_T\", y=\"ln_k\"))\n    + geom_ribbon(\n        aes(x=\"inv_T\", ymin=\"ci_lower\", ymax=\"ci_upper\"), data=df_fit, fill=BRAND, alpha=0.12, inherit_aes=False\n    )\n    + geom_line(aes(x=\"inv_T\", y=\"ln_k_fit\"), data=df_fit, color=BLUE, size=1.5, inherit_aes=False)\n    + geom_point(color=BRAND, size=4.5, stroke=0.8, shape=\"o\")\n    + scale_x_continuous(breaks=tick_positions, labels=tick_labels, expand=(0.05, 0))\n    + scale_y_continuous(expand=(0.08, 0))\n    + annotate(\n        \"label\",\n        x=anno_x,\n        y=anno_y_top,\n        label=anno_r2,\n        size=4.5,\n        color=INK,\n        fontweight=\"bold\",\n        ha=\"center\",\n        fill=ELEVATED_BG,\n        alpha=0.92,\n        label_padding=0.4,\n        label_size=0,\n    )\n    + annotate(\"text\", x=anno_x, y=anno_y_top - 0.9, label=anno_ea, size=4.0, color=INK, fontweight=\"bold\", ha=\"center\")\n    + annotate(\n        \"text\",\n        x=anno_x,\n        y=anno_y_top - 1.65,\n        label=anno_slope,\n        size=4.0,\n        color=INK_MUTED,\n        fontstyle=\"italic\",\n        ha=\"center\",\n    )\n    + labs(x=\"1/T (K⁻¹)\", y=\"ln(k)\", title=title)\n    + theme_minimal()\n    + theme(\n        figure_size=(8, 4.5),\n        plot_title=element_text(size=12, weight=\"bold\", color=INK, margin={\"b\": 10}),\n        axis_title=element_text(size=10, color=INK),\n        axis_text=element_text(size=8, color=INK_SOFT),\n        axis_ticks=element_line(color=INK_SOFT, size=0.3),\n        plot_background=element_rect(fill=PAGE_BG, color=PAGE_BG),\n        panel_background=element_rect(fill=PAGE_BG),\n        panel_grid_major_x=element_blank(),\n        panel_grid_minor=element_blank(),\n        panel_grid_major_y=element_line(color=INK, size=0.3, alpha=0.15),\n        axis_ticks_minor=element_blank(),\n        plot_margin=0.08,\n    )\n)\n\n# Save\nplot.save(f\"plot-{THEME}.png\", dpi=400, width=8, height=4.5, units=\"in\", verbose=False)\n"}