{"spec_id":"line-arrhenius","library":"plotly","language":"python","code":"\"\"\" anyplot.ai\nline-arrhenius: Arrhenius Plot for Reaction Kinetics\nLibrary: plotly 6.8.0 | Python 3.13.14\nQuality: 90/100 | Updated: 2026-06-24\n\"\"\"\n\nimport os\n\nimport numpy as np\nimport plotly.graph_objects as go\n\n\n# Theme\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\"\nGRID = \"rgba(26,26,23,0.15)\" if THEME == \"light\" else \"rgba(240,239,232,0.15)\"\n\n# Imprint palette\nBRAND = \"#009E73\"  # position 1 — data markers\nLINE_COLOR = \"#C475FD\"  # position 2 — regression line\n\n# Data — first-order decomposition reaction rate constants at various temperatures\ntemperature_K = np.array([300, 330, 360, 400, 440, 480, 520, 560, 600])\nactivation_energy = 75000  # J/mol (75 kJ/mol)\nR_gas = 8.314  # J/(mol·K)\npre_exponential = 1.2e10  # s⁻¹\n\nnp.random.seed(42)\nrate_constant_k = pre_exponential * np.exp(-activation_energy / (R_gas * temperature_K))\nrate_constant_k *= np.exp(np.random.normal(0, 0.20, len(temperature_K)))\n\n# Arrhenius transform (use 1000/T for cleaner axis values)\ninv_T = 1000 / temperature_K\nln_k = np.log(rate_constant_k)\n\n# Linear regression\ncoeffs = np.polyfit(inv_T, ln_k, 1)\nslope, intercept = coeffs[0], coeffs[1]\nln_k_pred = slope * inv_T + intercept\nss_res = np.sum((ln_k - ln_k_pred) ** 2)\nss_tot = np.sum((ln_k - np.mean(ln_k)) ** 2)\nr_squared = 1 - ss_res / ss_tot\nEa_extracted = -slope * R_gas * 1000  # factor of 1000 from using 1000/T\n\n# Fit line for display\ninv_T_fit = np.linspace(inv_T.min() - 0.05, inv_T.max() + 0.05, 200)\nln_k_fit = slope * inv_T_fit + intercept\n\n# Secondary x-axis tick values — temperature in K\ntemp_ticks = np.array([300, 350, 400, 450, 500, 550, 600])\ninv_T_ticks = 1000 / temp_ticks\nx_range_reversed = [inv_T_fit.max(), inv_T_fit.min()]\n\n# Plot\nfig = go.Figure()\n\n# Regression line (behind markers)\nfig.add_trace(\n    go.Scatter(\n        x=inv_T_fit,\n        y=ln_k_fit,\n        mode=\"lines\",\n        name=f\"Linear Fit (R² = {r_squared:.4f})\",\n        line={\"color\": LINE_COLOR, \"width\": 3},\n        hovertemplate=\"1000/T: %{x:.3f} K⁻¹<br>ln(k): %{y:.2f}<extra></extra>\",\n    )\n)\n\n# Experimental data points\nfig.add_trace(\n    go.Scatter(\n        x=inv_T,\n        y=ln_k,\n        mode=\"markers\",\n        name=\"Experimental Data\",\n        marker={\"size\": 18, \"color\": BRAND, \"line\": {\"color\": PAGE_BG, \"width\": 2}, \"symbol\": \"circle\"},\n        hovertemplate=(\n            \"<b>T = %{customdata[0]:.0f} K</b><br>\"\n            \"1000/T: %{x:.3f} K⁻¹<br>\"\n            \"ln(k): %{y:.2f}<br>\"\n            \"k: %{customdata[1]:.2e} s⁻¹<extra></extra>\"\n        ),\n        customdata=np.column_stack([temperature_K, rate_constant_k]),\n    )\n)\n\n# Invisible trace to activate secondary x-axis (required Plotly workaround)\nfig.add_trace(\n    go.Scatter(\n        x=inv_T,\n        y=ln_k,\n        mode=\"markers\",\n        marker={\"size\": 0.01, \"opacity\": 0},\n        showlegend=False,\n        xaxis=\"x2\",\n        hoverinfo=\"skip\",\n    )\n)\n\n# Activation energy annotation\nfig.add_annotation(\n    x=inv_T.mean(),\n    y=ln_k.max() - 0.3,\n    text=f\"<b>E<sub>a</sub> = {Ea_extracted / 1000:.1f} kJ/mol</b><br>R² = {r_squared:.4f}\",\n    showarrow=False,\n    font={\"size\": 14, \"color\": INK},\n    bgcolor=ELEVATED_BG,\n    bordercolor=INK_SOFT,\n    borderwidth=1,\n    borderpad=10,\n    align=\"left\",\n)\n\n# Layout\ntitle = \"line-arrhenius · python · plotly · anyplot.ai\"\nfig.update_layout(\n    autosize=False,\n    paper_bgcolor=PAGE_BG,\n    plot_bgcolor=PAGE_BG,\n    font={\"color\": INK},\n    title={\"text\": title, \"font\": {\"size\": 16, \"color\": INK}, \"x\": 0.5, \"xanchor\": \"center\"},\n    xaxis={\n        \"title\": {\"text\": \"1000 / T (K⁻¹)\", \"font\": {\"size\": 12, \"color\": INK}},\n        \"tickfont\": {\"size\": 10, \"color\": INK_SOFT},\n        \"showgrid\": False,\n        \"zeroline\": False,\n        \"linecolor\": INK_SOFT,\n        \"linewidth\": 1,\n        \"ticks\": \"outside\",\n        \"tickcolor\": INK_SOFT,\n        \"autorange\": \"reversed\",\n    },\n    xaxis2={\n        \"tickfont\": {\"size\": 10, \"color\": INK_SOFT},\n        \"tickvals\": inv_T_ticks.tolist(),\n        \"ticktext\": [f\"{t:.0f} K\" for t in temp_ticks],\n        \"overlaying\": \"x\",\n        \"side\": \"top\",\n        \"showgrid\": False,\n        \"zeroline\": False,\n        \"linecolor\": INK_SOFT,\n        \"linewidth\": 1,\n        \"ticks\": \"outside\",\n        \"tickcolor\": INK_SOFT,\n        \"range\": x_range_reversed,\n    },\n    yaxis={\n        \"title\": {\"text\": \"ln(k)\", \"font\": {\"size\": 12, \"color\": INK}},\n        \"tickfont\": {\"size\": 10, \"color\": INK_SOFT},\n        \"gridcolor\": GRID,\n        \"gridwidth\": 1,\n        \"zeroline\": False,\n        \"linecolor\": INK_SOFT,\n        \"linewidth\": 1,\n        \"ticks\": \"outside\",\n        \"tickcolor\": INK_SOFT,\n    },\n    legend={\n        \"font\": {\"size\": 10, \"color\": INK_SOFT},\n        \"x\": 0.02,\n        \"y\": 0.02,\n        \"xanchor\": \"left\",\n        \"yanchor\": \"bottom\",\n        \"bgcolor\": ELEVATED_BG,\n        \"bordercolor\": INK_SOFT,\n        \"borderwidth\": 1,\n    },\n    margin={\"l\": 80, \"r\": 40, \"t\": 100, \"b\": 60},\n)\n\n# Save\nfig.write_image(f\"plot-{THEME}.png\", width=800, height=450, scale=4)\nfig.write_html(f\"plot-{THEME}.html\", include_plotlyjs=\"cdn\")\n"}