Arrhenius Plot for Reaction Kinetics — Makie.jl

An Arrhenius plot displays ln(k) versus 1/T to determine the activation energy of a chemical reaction from experimental rate constant data. The Arrhenius equation predicts a linear relationship on this transformed scale, where the slope equals -Ea/R (activation energy divided by the gas constant). This visualization is fundamental in physical chemistry and chemical engineering for characterizing reaction kinetics and comparing catalytic performance.

Arrhenius Plot for Reaction Kinetics rendered with Makie.jl

Renders

Julia source (Makie.jl)

# anyplot.ai
# line-arrhenius: Arrhenius Plot for Reaction Kinetics
# Library: makie 0.22.10 | Julia 1.11.9
# Quality: 84/100 | Created: 2026-06-24

using CairoMakie
using Colors
using Random
using Statistics
using Printf

Random.seed!(42)

# Theme tokens
const THEME       = get(ENV, "ANYPLOT_THEME", "light")
const PAGE_BG     = THEME == "light" ? colorant"#FAF8F1" : colorant"#1A1A17"
const ELEVATED_BG = THEME == "light" ? colorant"#FFFDF6" : colorant"#242420"
const INK         = THEME == "light" ? colorant"#1A1A17" : colorant"#F0EFE8"
const INK_SOFT    = THEME == "light" ? colorant"#4A4A44" : colorant"#B8B7B0"

const IMPRINT_PALETTE = [
    colorant"#009E73", colorant"#C475FD", colorant"#4467A3", colorant"#BD8233",
    colorant"#AE3030", colorant"#2ABCCD", colorant"#954477", colorant"#99B314",
]

# Arrhenius data: first-order thermal decomposition
# k = A * exp(-Ea / R / T),  Ea = 80 kJ/mol,  A = 1e10 s⁻¹
const R_GAS = 8.314     # J mol⁻¹ K⁻¹
const EA    = 80_000.0  # J mol⁻¹
const A_PRE = 1.0e10    # s⁻¹

temperatures_K = [300.0, 330.0, 360.0, 400.0, 440.0, 480.0, 520.0, 560.0, 600.0]
k_ideal        = A_PRE .* exp.(-EA ./ (R_GAS .* temperatures_K))
rate_constants = k_ideal .* (1.0 .+ 0.04 .* randn(length(temperatures_K)))

# Arrhenius linearisation using 1000/T on x-axis (conventional; avoids tiny tick numbers)
inv_T_scaled = 1000.0 ./ temperatures_K  # values ≈ 1.67 – 3.33
ln_k         = log.(rate_constants)

# Linear regression: ln(k) = slope * (1000/T) + intercept
x_bar = mean(inv_T_scaled)
y_bar = mean(ln_k)
slope     = sum((inv_T_scaled .- x_bar) .* (ln_k .- y_bar)) /
            sum((inv_T_scaled .- x_bar).^2)
intercept = y_bar - slope * x_bar

ln_k_fit = slope .* inv_T_scaled .+ intercept
r_sq     = 1.0 - sum((ln_k .- ln_k_fit).^2) / sum((ln_k .- y_bar).^2)

# Ea from slope: since x = 1000/T, slope × 1000 = -Ea/R
ea_kJmol = -slope * R_GAS  # ≈ 79.9 kJ/mol

# Extended regression line
margin = 0.08 * (maximum(inv_T_scaled) - minimum(inv_T_scaled))
x_fit  = collect(range(minimum(inv_T_scaled) - margin,
                       maximum(inv_T_scaled) + margin; length = 200))
y_fit  = slope .* x_fit .+ intercept

# 95% confidence band (t_{0.025, df=7} = 2.365)
n_pts   = length(inv_T_scaled)
sse     = sum((ln_k .- ln_k_fit).^2)
s2      = sse / (n_pts - 2)
Sxx     = sum((inv_T_scaled .- x_bar).^2)
t_crit  = 2.365
se_band = sqrt.(s2 .* (1.0 / n_pts .+ (x_fit .- x_bar).^2 ./ Sxx))
y_upper = y_fit .+ t_crit .* se_band
y_lower = y_fit .- t_crit .* se_band

title_str  = "line-arrhenius · julia · makie · anyplot.ai"
title_size = length(title_str) > 67 ? max(14, round(Int, 20 * 67 / length(title_str))) : 20

fig = Figure(
    size            = (1600, 900),
    fontsize        = 14,
    backgroundcolor = PAGE_BG,
)

ax = Axis(
    fig[1, 1];
    title              = title_str,
    titlesize          = title_size,
    titlecolor         = INK,
    xlabel             = "10³/T  (K⁻¹)",
    ylabel             = "ln(k)",
    xlabelsize         = 16,
    ylabelsize         = 16,
    xticklabelsize     = 13,
    yticklabelsize     = 13,
    xlabelcolor        = INK,
    ylabelcolor        = INK,
    xticklabelcolor    = INK_SOFT,
    yticklabelcolor    = INK_SOFT,
    xtickcolor         = INK_SOFT,
    ytickcolor         = INK_SOFT,
    backgroundcolor    = PAGE_BG,
    topspinevisible    = false,
    rightspinevisible  = false,
    leftspinecolor     = INK_SOFT,
    bottomspinecolor   = INK_SOFT,
    xgridvisible       = false,
    ygridvisible       = true,
    xminorgridvisible  = false,
    yminorgridvisible  = false,
    ygridcolor         = RGBAf(INK.r, INK.g, INK.b, 0.12),
    xticks             = LinearTicks(4),
)

# True secondary x-axis: temperature reference in K (overlapping Axis at top)
ax_top = Axis(
    fig[1, 1];
    xaxisposition      = :top,
    yaxisposition      = :right,
    backgroundcolor    = :transparent,
    topspinevisible    = true,
    topspinecolor      = INK_SOFT,
    bottomspinevisible = false,
    leftspinevisible   = false,
    rightspinevisible  = false,
    xgridvisible       = false,
    ygridvisible       = false,
    yticksvisible      = false,
    yticklabelsvisible = false,
    xlabel             = "Temperature (K)",
    xlabelsize         = 13,
    xlabelcolor        = INK_SOFT,
    xticklabelsize     = 11,
    xticklabelcolor    = INK_SOFT,
    xtickcolor         = INK_SOFT,
    xticks             = (
        1000.0 ./ [300.0, 350.0, 400.0, 500.0, 600.0],
        ["300", "350", "400", "500", "600"],
    ),
)
linkxaxes!(ax, ax_top)
linkyaxes!(ax, ax_top)

# Confidence band (Makie band! — highlights fit quality)
band!(ax, x_fit, y_lower, y_upper;
    color = (IMPRINT_PALETTE[3], 0.15),
)

# Regression line (drawn before markers so they render on top)
lines!(ax, x_fit, y_fit;
    color     = IMPRINT_PALETTE[3],
    linewidth = 2.5,
    linestyle = :dash,
    label     = "Linear fit (Arrhenius)",
)

# Experimental data points
scatter!(ax, inv_T_scaled, ln_k;
    color       = IMPRINT_PALETTE[1],
    markersize  = 14,
    strokewidth = 1.5,
    strokecolor = PAGE_BG,
    label       = "Measured k(T)",
)

# Annotation: kinetic parameters — lower-left corner
x_range = maximum(inv_T_scaled) - minimum(inv_T_scaled)
y_range = maximum(ln_k) - minimum(ln_k)
x_ann   = minimum(inv_T_scaled) + 0.03 * x_range
y_ann   = minimum(ln_k) + 0.08 * y_range

text!(ax, x_ann, y_ann;
    text     = @sprintf("-Ea/R = %d K\nEa = %.1f kJ mol⁻¹\nR² = %.4f",
                   round(Int, -slope * 1000.0), ea_kJmol, r_sq),
    color    = INK,
    fontsize = 12,
    align    = (:left, :bottom),
)

axislegend(ax;
    position        = :rt,
    labelsize       = 12,
    framevisible    = true,
    framecolor      = INK_SOFT,
    backgroundcolor = ELEVATED_BG,
    labelcolor      = INK,
)

resize_to_layout!(fig)
save("plot-$(THEME).png", fig; px_per_unit = 2)

Part of Arrhenius Plot for Reaction Kinetics on anyplot.ai.

Other implementations