{"spec_id":"line-arrhenius","library":"letsplot","language":"python","code":"\"\"\" anyplot.ai\nline-arrhenius: Arrhenius Plot for Reaction Kinetics\nLibrary: letsplot 4.10.1 | Python 3.13.14\nQuality: 89/100 | Updated: 2026-06-24\n\"\"\"\n\nimport os\n\nimport numpy as np\nimport pandas as pd\nfrom lets_plot import *\nfrom lets_plot import ggsave\nfrom scipy import stats\n\n\nLetsPlot.setup_html()\n\nTHEME = os.getenv(\"ANYPLOT_THEME\", \"light\")\n\n# Imprint palette — position 1 (brand green) for first/only series\nBRAND = \"#009E73\"\n\n# Theme-adaptive chrome\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# Data — first-order decomposition reaction rate constants at various temperatures\nnp.random.seed(42)\ntemperature_K = np.array([300, 325, 350, 375, 400, 425, 450, 475, 500, 550, 600])\nR = 8.314  # gas constant (J/(mol·K))\nEa_true = 75000  # activation energy (J/mol) ~75 kJ/mol\nA_true = 1e12  # pre-exponential factor (s⁻¹)\n\nrate_constant_k = A_true * np.exp(-Ea_true / (R * temperature_K))\nnoise = np.random.normal(0, 0.15, len(temperature_K))\nln_k = np.log(rate_constant_k) + noise\n\ninv_T = 1.0 / temperature_K\n\n# Linear regression for annotation values\nslope, intercept, r_value, _, _ = stats.linregress(inv_T, ln_k)\nr_squared = r_value**2\nEa_extracted = -slope * R / 1000  # kJ/mol\n\ndf_points = pd.DataFrame(\n    {\n        \"inv_T\": inv_T,\n        \"ln_k\": ln_k,\n        \"temp_K\": [f\"{t} K\" for t in temperature_K],\n        \"k_val\": [f\"{np.exp(lk):.2e}\" for lk in ln_k],\n    }\n)\n\n# Annotation text for regression parameters\neq_text = f\"Slope = −Ea/R = {slope:.0f} K\\nEa = {Ea_extracted:.1f} kJ/mol\\nR² = {r_squared:.4f}\"\ny_range = ln_k.max() - ln_k.min()\nannot_x = inv_T.max() - (inv_T.max() - inv_T.min()) * 0.02\nannot_y = ln_k.min() + y_range * 0.25\n\n# Secondary x-axis: temperature labels at top of plot (manual, lets-plot limitation)\ntemp_ticks = np.array([600, 500, 450, 400, 350, 300])\ninv_T_ticks = 1.0 / temp_ticks\ny_top = ln_k.max() + y_range * 0.08\n\ndf_ticks = pd.DataFrame(\n    {\n        \"inv_T\": inv_T_ticks,\n        \"y_label\": [y_top] * len(temp_ticks),\n        \"y_tick_start\": [y_top - y_range * 0.02] * len(temp_ticks),\n        \"y_tick_end\": [y_top - y_range * 0.04] * len(temp_ticks),\n        \"label\": [f\"{t} K\" for t in temp_ticks],\n    }\n)\ndf_title = pd.DataFrame(\n    {\"inv_T\": [np.mean(inv_T_ticks)], \"y_label\": [y_top + y_range * 0.06], \"label\": [\"Temperature (K)\"]}\n)\n\nanyplot_theme = theme(\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_major_y=element_line(color=INK_SOFT, size=0.3),\n    panel_grid_minor=element_blank(),\n    panel_border=element_blank(),\n    axis_line=element_line(color=INK_SOFT),\n    axis_ticks=element_blank(),\n    axis_ticks_length=0,\n    axis_title=element_text(size=12, color=INK),\n    axis_text=element_text(size=10, color=INK_SOFT),\n    plot_title=element_text(size=16, color=INK, face=\"bold\"),\n    plot_margin=[40, 40, 20, 20],\n)\n\nplot = (\n    ggplot()\n    # Confidence band + regression line via geom_smooth\n    + geom_smooth(\n        aes(x=\"inv_T\", y=\"ln_k\"),\n        data=df_points,\n        method=\"lm\",\n        color=BRAND,\n        size=1.5,\n        alpha=0.30,\n        se=True,\n        level=0.95,\n    )\n    # Data points with tooltips\n    + geom_point(\n        aes(x=\"inv_T\", y=\"ln_k\"),\n        data=df_points,\n        fill=BRAND,\n        color=PAGE_BG,\n        size=4,\n        shape=21,\n        stroke=1.2,\n        tooltips=layer_tooltips()\n        .line(\"@temp_K\")\n        .line(\"1/T = @inv_T\")\n        .line(\"ln(k) = @ln_k\")\n        .line(\"k = @k_val\"),\n    )\n    # Regression parameters annotation\n    + geom_text(\n        aes(x=\"x\", y=\"y\", label=\"label\"),\n        data=pd.DataFrame({\"x\": [annot_x], \"y\": [annot_y], \"label\": [eq_text]}),\n        size=4.5,\n        color=INK_SOFT,\n        hjust=1,\n    )\n    # Secondary axis: temperature tick labels\n    + geom_text(\n        aes(x=\"inv_T\", y=\"y_label\", label=\"label\"),\n        data=df_ticks,\n        size=4.5,\n        color=INK_SOFT,\n    )\n    + geom_segment(\n        aes(x=\"inv_T\", y=\"y_tick_start\", xend=\"inv_T\", yend=\"y_tick_end\"),\n        data=df_ticks,\n        color=INK_MUTED,\n        size=0.5,\n    )\n    # Secondary axis title\n    + geom_text(\n        aes(x=\"inv_T\", y=\"y_label\", label=\"label\"),\n        data=df_title,\n        size=4,\n        color=INK_SOFT,\n        fontface=\"italic\",\n    )\n    + labs(\n        x=\"1/T (K⁻¹)\", y=\"ln(k)\", title=\"line-arrhenius · python · letsplot · anyplot.ai\"\n    )\n    + scale_x_continuous(\n        breaks=inv_T_ticks.tolist(), labels=[f\"{v:.2e}\" for v in inv_T_ticks]\n    )\n    + scale_y_continuous(\n        limits=[ln_k.min() - y_range * 0.08, y_top + y_range * 0.10]\n    )\n    + coord_cartesian(xlim=[inv_T.min() * 0.95, inv_T.max() * 1.05])\n    + ggsize(800, 450)\n    + anyplot_theme\n)\n\nggsave(plot, f\"plot-{THEME}.png\", path=\".\", scale=4)\nggsave(plot, f\"plot-{THEME}.html\", path=\".\")\n"}