{"spec_id":"bar-pareto","library":"makie","language":"julia","code":"# anyplot.ai\n# bar-pareto: Pareto Chart with Cumulative Line\n# Library: makie 0.22.10 | Julia 1.11.9\n# Quality: 88/100 | Created: 2026-06-20\n\nusing CairoMakie\nusing Colors\nusing Random\n\nRandom.seed!(42)\n\n# Theme tokens\nconst THEME       = get(ENV, \"ANYPLOT_THEME\", \"light\")\nconst PAGE_BG     = THEME == \"light\" ? colorant\"#FAF8F1\" : colorant\"#1A1A17\"\nconst ELEVATED_BG = THEME == \"light\" ? colorant\"#FFFDF6\" : colorant\"#242420\"\nconst INK         = THEME == \"light\" ? colorant\"#1A1A17\" : colorant\"#F0EFE8\"\nconst INK_SOFT    = THEME == \"light\" ? colorant\"#4A4A44\" : colorant\"#B8B7B0\"\n\nconst IMPRINT_PALETTE = [\n    colorant\"#009E73\",  # 1 — brand green (first series)\n    colorant\"#C475FD\",  # 2 — lavender\n    colorant\"#4467A3\",  # 3 — blue\n    colorant\"#BD8233\",  # 4 — ochre\n    colorant\"#AE3030\",  # 5 — matte red (semantic: threshold / error)\n    colorant\"#2ABCCD\",  # 6 — cyan\n    colorant\"#954477\",  # 7 — rose\n    colorant\"#99B314\",  # 8 — lime\n]\n\n# Data — e-commerce support ticket categories, sorted descending by volume\ncategories = [\"Billing Issues\", \"Login Problems\", \"Delivery Delays\",\n              \"Product Damage\", \"Wrong Item\", \"App Crashes\", \"Other\"]\ncounts     = [342, 289, 213, 178, 145, 98, 65]\n\nn       = length(categories)\ntotal   = sum(counts)\ncum_pct = cumsum(counts) ./ total .* 100\nxs      = collect(1:n)\n\n# Interpolated x where cumulative line crosses 80% (for crossing annotation)\ncross_idx = findfirst(cum_pct .>= 80.0)\ncross_x   = xs[cross_idx - 1] +\n            (80.0 - cum_pct[cross_idx - 1]) /\n            (cum_pct[cross_idx] - cum_pct[cross_idx - 1])\n\n# --- Figure ------------------------------------------------------------------\nfig = Figure(\n    size            = (1600, 900),\n    fontsize        = 14,\n    backgroundcolor = PAGE_BG,\n)\n\n# Primary axis: bars (left y = ticket counts)\nax1 = Axis(\n    fig[1, 1];\n    title              = \"bar-pareto · julia · makie · anyplot.ai\",\n    titlesize          = 20,\n    titlecolor         = INK,\n    xlabel             = \"Issue Category\",\n    ylabel             = \"Ticket Count\",\n    xlabelcolor        = INK,\n    ylabelcolor        = INK,\n    xticklabelcolor    = INK_SOFT,\n    yticklabelcolor    = INK_SOFT,\n    xtickcolor         = INK_SOFT,\n    ytickcolor         = INK_SOFT,\n    leftspinecolor     = INK_SOFT,\n    bottomspinecolor   = INK_SOFT,\n    topspinevisible    = false,\n    rightspinevisible  = false,\n    backgroundcolor    = PAGE_BG,\n    xticks             = (xs, categories),\n    xticklabelrotation = π / 4,\n    xticklabelalign    = (:right, :top),\n    xticklabelsize     = 12,\n    yticklabelsize     = 12,\n    xlabelsize         = 14,\n    ylabelsize         = 14,\n    xgridvisible       = false,\n    ygridcolor         = RGBAf(INK.r, INK.g, INK.b, 0.15f0),\n    yminorgridvisible  = false,\n    xminorgridvisible  = false,\n)\n\n# Secondary axis: cumulative % line (right y = 0–100%)\nax2 = Axis(\n    fig[1, 1];\n    yaxisposition      = :right,\n    ylabel             = \"Cumulative %\",\n    ylabelcolor        = INK,\n    yticklabelcolor    = INK_SOFT,\n    ytickcolor         = INK_SOFT,\n    rightspinecolor    = INK_SOFT,\n    topspinevisible    = false,\n    leftspinevisible   = false,\n    bottomspinevisible = false,\n    backgroundcolor    = :transparent,\n    yticks             = (collect(0:20:100), [\"0%\", \"20%\", \"40%\", \"60%\", \"80%\", \"100%\"]),\n    yticklabelsize     = 12,\n    ylabelsize         = 14,\n    xgridvisible       = false,\n    ygridvisible       = false,\n)\nhidexdecorations!(ax2)\nlinkxaxes!(ax1, ax2)\nylims!(ax2, 0, 110)\n\n# --- Bars (descending order, Imprint brand green) ----------------------------\nbarplot!(ax1, xs, counts;\n    color       = IMPRINT_PALETTE[1],\n    strokecolor = PAGE_BG,\n    strokewidth = 1,\n    gap         = 0.15,\n)\n\n# --- 80% threshold line (matte red dashed — semantic anchor for threshold) ---\nhlines!(ax2, [80.0];\n    color     = IMPRINT_PALETTE[5],\n    linestyle = :dash,\n    linewidth = 1.8,\n)\n\n# --- Cumulative % line with markers at bar centers ---------------------------\nlines!(ax2, xs, cum_pct;\n    color     = IMPRINT_PALETTE[3],\n    linewidth = 2.5,\n)\nscatter!(ax2, xs, cum_pct;\n    color        = IMPRINT_PALETTE[3],\n    markersize   = 10,\n    strokewidth  = 1.0,\n    strokecolor  = PAGE_BG,\n)\n\n# --- 80% crossing annotation: diamond + label reveal the \"vital few\" --------\nscatter!(ax2, [cross_x], [80.0];\n    color       = IMPRINT_PALETTE[5],\n    marker      = :diamond,\n    markersize  = 14,\n    strokewidth = 1.5,\n    strokecolor = PAGE_BG,\n)\ntext!(ax2, [cross_x + 0.2], [89.0];\n    text     = [\"Top $(cross_idx) of $(n) categories\"],\n    color    = INK,\n    fontsize = 11,\n    align    = [(:left, :bottom)],\n)\n\n# --- Legend ------------------------------------------------------------------\nLegend(\n    fig[1, 2],\n    [\n        PolyElement(color = IMPRINT_PALETTE[1], strokecolor = PAGE_BG, strokewidth = 1),\n        LineElement(color = IMPRINT_PALETTE[3], linewidth = 2.5),\n        LineElement(color = IMPRINT_PALETTE[5], linestyle = :dash, linewidth = 1.8),\n    ],\n    [\"Ticket Count\", \"Cumulative %\", \"80% Threshold\"],\n    framecolor       = INK_SOFT,\n    backgroundcolor  = ELEVATED_BG,\n    labelcolor  = INK,\n    labelsize   = 11,\n    patchsize   = (24, 10),\n    margin      = (8, 8, 8, 8),\n)\n\n# --- Save --------------------------------------------------------------------\nsave(\"plot-$(THEME).png\", fig; px_per_unit = 2)\n"}