{"spec_id":"bar-error","library":"makie","language":"julia","code":"# anyplot.ai\n# bar-error: Bar Chart with Error Bars\n# Library: makie 0.21.9 | Julia 1.11.9\n# Quality: 90/100 | Created: 2026-09-02\n\nusing CairoMakie\nusing Colors\nusing Random\nusing Statistics\n\nRandom.seed!(42)\n\n# Theme tokens (see prompts/default-style-guide.md \"Theme-adaptive Chrome\")\nTHEME    = get(ENV, \"ANYPLOT_THEME\", \"light\")\nPAGE_BG  = THEME == \"light\" ? colorant\"#FAF8F1\" : colorant\"#1A1A17\"\nINK      = THEME == \"light\" ? colorant\"#1A1A17\" : colorant\"#F0EFE8\"\nINK_SOFT = THEME == \"light\" ? colorant\"#4A4A44\" : colorant\"#B8B7B0\"\nBRAND    = colorant\"#009E73\"  # Imprint palette position 1 — ALWAYS first series\n\n# Data — 30 simulated runs per catalyst, drawn from each catalyst's known\n# reaction-yield distribution; mean/SD are derived from the runs themselves\n# (not hardcoded) so the seeded RNG actually drives the summary statistics.\ncatalysts = [\"Pd/C\", \"Pt/C\", \"Ru/C\", \"Ni\", \"Cu\", \"Fe\"]\ntrue_mean = [87.4, 82.1, 74.9, 71.6, 63.8, 54.2]\ntrue_std  = [3.1, 4.6, 5.2, 5.8, 6.9, 8.1]\nn_runs = 30\n\nruns = [tm .+ ts .* randn(n_runs) for (tm, ts) in zip(true_mean, true_std)]\nmean_yield = mean.(runs)\nstd_yield = std.(runs)\nx = 1:length(catalysts)\nbest = argmax(mean_yield)\n\n# Plot — see default-style-guide.md \"Visual Sizing Defaults\" and prompts/library/makie.md\nfig = Figure(\n    size            = (1600, 900),\n    fontsize        = 14,\n    backgroundcolor = PAGE_BG,\n)\n\nax = Axis(\n    fig[1, 1];\n    title             = \"bar-error · julia · makie · anyplot.ai\",\n    titlesize         = 20,\n    titlecolor        = INK,\n    subtitle          = \"Error bars: ±1 SD (n = 30 runs per catalyst)\",\n    subtitlesize      = 14,\n    subtitlecolor     = INK_SOFT,\n    xlabel            = \"Catalyst\",\n    ylabel            = \"Reaction Yield (%)\",\n    xlabelsize        = 14,\n    ylabelsize        = 14,\n    xlabelcolor       = INK,\n    ylabelcolor       = INK,\n    xticklabelsize    = 12,\n    yticklabelsize    = 12,\n    xticklabelcolor   = INK_SOFT,\n    yticklabelcolor   = INK_SOFT,\n    xticks            = (x, catalysts),\n    backgroundcolor   = PAGE_BG,\n    topspinevisible   = false,\n    rightspinevisible = false,\n    leftspinecolor    = INK_SOFT,\n    bottomspinecolor  = INK_SOFT,\n    xgridvisible      = false,\n    ygridcolor        = RGBAf(INK.r, INK.g, INK.b, 0.15),\n    xminorgridvisible = false,\n    yminorgridvisible = false,\n)\n\nbarplot!(ax, x, mean_yield;\n    color       = BRAND,\n    strokecolor = PAGE_BG,\n    strokewidth = 1.5,\n    width       = 0.6,\n)\n\n# Raincloud-style overlay: jittered individual runs, hinting at the\n# per-catalyst distribution the bar+error-bar summary is drawn from.\njitter_x = vcat([fill(xi, n_runs) .+ (rand(n_runs) .- 0.5) .* 0.32 for xi in x]...)\njitter_y = vcat(runs...)\nscatter!(ax, jitter_x, jitter_y;\n    color       = (INK, 0.22),\n    markersize  = 5,\n    strokewidth = 0,\n)\n\nerrorbars!(ax, x, mean_yield, std_yield;\n    color        = INK,\n    linewidth    = 2,\n    whiskerwidth = 18,\n)\n\n# Callout on the top-performing catalyst — gives the sorted bars an\n# explicit focal point instead of relying on descending order alone.\ntext!(ax, x[best], mean_yield[best] + std_yield[best];\n    text      = \"★ Top performer\",\n    color     = INK,\n    fontsize  = 13,\n    font      = :bold,\n    align     = (:center, :bottom),\n    offset    = (0, 6),\n)\n\nylims!(ax, 0, maximum(mean_yield .+ std_yield) * 1.18)\n\n# Save\nsave(\"plot-$(THEME).png\", fig; px_per_unit = 2)\n"}