{"spec_id":"area-stacked-confidence","library":"makie","language":"julia","code":"# anyplot.ai\n# area-stacked-confidence: Stacked Area Chart with Confidence Bands\n# Library: makie 0.21.9 | Julia 1.11.9\n# Quality: 81/100 | Created: 2026-08-26\n\nusing CairoMakie\nusing Colors\nusing Random\n\nRandom.seed!(42)\n\n# --- Theme tokens (see prompts/default-style-guide.md \"Theme-adaptive Chrome\") ---\nconst THEME    = get(ENV, \"ANYPLOT_THEME\", \"light\")\nconst PAGE_BG  = THEME == \"light\" ? colorant\"#FAF8F1\" : colorant\"#1A1A17\"\nconst INK      = THEME == \"light\" ? colorant\"#1A1A17\" : colorant\"#F0EFE8\"\nconst INK_SOFT = THEME == \"light\" ? colorant\"#4A4A44\" : colorant\"#B8B7B0\"\n\n# Imprint categorical palette — first series is ALWAYS #009E73\nconst IMPRINT_PALETTE = [\n    colorant\"#009E73\",  # 1 — brand green\n    colorant\"#C475FD\",  # 2 — lavender\n    colorant\"#4467A3\",  # 3 — blue\n]\n\n# --- Data: quarterly revenue forecast by product line, 90% prediction interval ---\nn_quarters = 24\nquarters = collect(1:n_quarters)\nproduct_lines = [\"Core Platform\", \"Cloud Services\", \"Emerging Markets\"]\n\nbase_revenue = [18.0, 9.0, 5.0]     # starting quarterly revenue ($M)\ntrend        = [0.55, 0.65, 0.35]   # quarterly growth ($M)\nnoise_scale  = [0.9, 0.8, 0.6]\npi_base      = [0.6, 0.7, 0.9]      # starting half-width of the 90% interval ($M)\npi_growth    = [0.22, 0.30, 0.42]   # interval widening rate with forecast horizon\n\nrevenue = Matrix{Float64}(undef, n_quarters, 3)\nhalf_width = Matrix{Float64}(undef, n_quarters, 3)\nfor i in 1:3\n    revenue[:, i] = base_revenue[i] .+ trend[i] .* (quarters .- 1) .+\n                    noise_scale[i] .* randn(n_quarters)\n    half_width[:, i] = pi_base[i] .+ pi_growth[i] .* sqrt.(quarters .- 1)\nend\n\ncum_top = cumsum(revenue, dims = 2)\ncum_baseline = hcat(zeros(n_quarters), cum_top[:, 1:2])\nband_lower = cum_top .- half_width\nband_upper = cum_top .+ half_width\n\nquarter_labels = [\"Q$(mod1(q, 4))'$(24 + div(q - 1, 4))\" for q in quarters]\ntick_idx = 1:4:n_quarters\n\n# --- Plot ---------------------------------------------------------------------\nfig = Figure(\n    resolution      = (1600, 900),\n    fontsize        = 14,\n    backgroundcolor = PAGE_BG,\n)\n\nax = Axis(\n    fig[1, 1];\n    title             = \"area-stacked-confidence · julia · makie · anyplot.ai\",\n    titlesize         = 20,\n    titlecolor        = INK,\n    xlabel            = \"Fiscal Quarter\",\n    ylabel            = \"Revenue (\\$M, cumulative)\",\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    xtickcolor        = INK_SOFT,\n    ytickcolor        = INK_SOFT,\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    xticks             = (quarters[tick_idx], quarter_labels[tick_idx]),\n    xticklabelrotation = 0.35,\n)\nhidexdecorations!(ax; grid = false, minorgrid = false)\n\n# Stacked areas drawn first (opaque), then confidence bands overlaid\n# (semi-transparent so overlap with the next layer stays legible), then\n# boundary lines on top.\nfor i in 1:3\n    band!(ax, quarters, cum_baseline[:, i], cum_top[:, i];\n          color = (IMPRINT_PALETTE[i], 0.85))\nend\nfor i in 1:3\n    band!(ax, quarters, band_lower[:, i], band_upper[:, i];\n          color = (IMPRINT_PALETTE[i], 0.28))\nend\nfor i in 1:3\n    lines!(ax, quarters, cum_top[:, i]; color = IMPRINT_PALETTE[i], linewidth = 2.5)\nend\n\nlegend_elements = vcat(\n    [PolyElement(color = (IMPRINT_PALETTE[i], 0.85)) for i in 1:3],\n    [PolyElement(color = (INK_SOFT, 0.28))],\n)\nlegend_labels = vcat(product_lines, [\"90% prediction interval\"])\nLegend(\n    fig[1, 2], legend_elements, legend_labels;\n    framevisible    = false,\n    labelcolor      = INK,\n    backgroundcolor = PAGE_BG,\n)\ncolsize!(fig.layout, 1, Relative(0.8))\n\n# Second linked Axis: the combined 90% PI half-width across all three stacked\n# series, sharing the x-axis with the main plot. This turns the widening\n# bands (visible but implicit above) into the chart's explicit headline\n# insight, using Makie's native multi-panel `linkxaxes!` layout rather than a\n# single fill_between-style band chart.\ntotal_half_width = vec(sum(half_width, dims = 2))\n\nax2 = Axis(\n    fig[2, 1];\n    xlabel              = \"Fiscal Quarter\",\n    ylabel              = \"Combined 90% PI\\nhalf-width (\\$M)\",\n    xlabelsize          = 14,\n    ylabelsize          = 12,\n    xlabelcolor         = INK,\n    ylabelcolor         = INK_SOFT,\n    xticklabelsize      = 12,\n    yticklabelsize      = 10,\n    xticklabelcolor     = INK_SOFT,\n    yticklabelcolor     = INK_SOFT,\n    xtickcolor          = INK_SOFT,\n    ytickcolor          = INK_SOFT,\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    xticks              = (quarters[tick_idx], quarter_labels[tick_idx]),\n    xticklabelrotation  = 0.35,\n)\nband!(ax2, quarters, zeros(n_quarters), total_half_width; color = (INK_SOFT, 0.28))\nlines!(ax2, quarters, total_half_width; color = INK_SOFT, linewidth = 2)\ntext!(\n    ax2, quarters[end], total_half_width[end] - 0.35;\n    text  = \"±$(round(total_half_width[end], digits = 1))M by Q1'29\",\n    align = (:right, :top),\n    color = INK,\n    fontsize = 12,\n)\nlinkxaxes!(ax, ax2)\nrowsize!(fig.layout, 1, Relative(0.74))\nrowsize!(fig.layout, 2, Relative(0.26))\n\n# --- Save -----------------------------------------------------------------\nsave(\"plot-$(THEME).png\", fig; px_per_unit = 2)\n"}