{"spec_id":"lollipop-grouped","library":"makie","language":"julia","code":"# anyplot.ai\n# lollipop-grouped: Grouped Lollipop Chart\n# Library: makie 0.21.9 | Julia 1.11.9\n# Quality: 88/100 | Created: 2026-09-02\n\nusing CairoMakie\nusing Colors\nusing Random\n\nRandom.seed!(42)\n\n# --- Theme tokens -------------------------------------------------------\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\"\nGRID_COLOR = RGBAf(INK.r, INK.g, INK.b, 0.15)\n\nIMPRINT_PALETTE = [\n    colorant\"#009E73\", colorant\"#C475FD\", colorant\"#4467A3\", colorant\"#BD8233\",\n    colorant\"#AE3030\", colorant\"#2ABCCD\", colorant\"#954477\", colorant\"#99B314\",\n]\n\n# --- Data -----------------------------------------------------------------\n# Quarterly revenue ($M) by product line, across regions. Regions are\n# pre-sorted by total revenue descending so the chart reveals the ranking.\nregions = [\"North America\", \"Asia Pacific\", \"Europe\", \"Latin America\"]\nproduct_lines = [\"Software\", \"Hardware\", \"Services\"]\n\nrevenue = [\n    82.0 61.0 34.0\n    91.0 58.0 22.0\n    68.0 69.0 29.0\n    37.0 26.0 15.0\n]\n\nn_regions = length(regions)\nn_series = length(product_lines)\n\n# Discrete Makie colormap built from the Imprint palette — series are colored\n# by mapping their integer index through this colormap (colorrange = (1,\n# n_series)) rather than indexing IMPRINT_PALETTE[j] by hand at each call.\nseries_cmap = cgrad(IMPRINT_PALETTE[1:n_series]; categorical = true)\n\n# Category band centers (top-to-bottom = first-to-last region) with a\n# small side-by-side offset per series inside each band.\ncategory_y = collect(n_regions:-1:1)\noffsets = range(-0.25, 0.25; length = n_series)\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 = \"Quarterly Revenue by Region and Product Line · lollipop-grouped · julia · makie · anyplot.ai\",\n    titlesize = 15,\n    titlecolor = INK,\n    xlabel = \"Quarterly Revenue (\\$M)\",\n    xlabelsize = 14,\n    xlabelcolor = INK,\n    xticklabelsize = 13,\n    xticklabelcolor = INK_SOFT,\n    yticklabelsize = 14,\n    yticklabelcolor = INK_SOFT,\n    backgroundcolor = PAGE_BG,\n    topspinevisible = false,\n    rightspinevisible = false,\n    leftspinecolor = INK_SOFT,\n    bottomspinecolor = INK_SOFT,\n    xtickcolor = INK_SOFT,\n    ytickcolor = INK_SOFT,\n    yticksvisible = false,\n    xgridcolor = GRID_COLOR,\n    ygridvisible = false,\n    xminorgridvisible = false,\n)\nax.yticks = (category_y, regions)\nxlims!(ax, 0, 105)\nylims!(ax, 0.3, n_regions + 0.7)\n\nfor j in 1:n_series\n    ys = [category_y[i] + offsets[j] for i in 1:n_regions]\n    xs = [revenue[i, j] for i in 1:n_regions]\n\n    for i in 1:n_regions\n        lines!(\n            ax, [0.0, xs[i]], [ys[i], ys[i]];\n            color = j, colormap = series_cmap, colorrange = (1, n_series),\n            linewidth = 3,\n        )\n    end\n\n    scatter!(\n        ax, xs, ys;\n        color = fill(j, n_regions),\n        colormap = series_cmap,\n        colorrange = (1, n_series),\n        markersize = 26,\n        strokewidth = 1.5,\n        strokecolor = PAGE_BG,\n    )\nend\n\n# Manual legend: colormap-mapped scatter/lines don't expose a per-series\n# solid color for axislegend to sample, so the swatches are built explicitly\n# from the same Imprint palette slots used for the plotted series.\nlegend_elements = [\n    MarkerElement(; color = IMPRINT_PALETTE[j], marker = :circle, markersize = 18)\n    for j in 1:n_series\n]\naxislegend(\n    ax, legend_elements, product_lines;\n    position = :rb, framevisible = false, labelcolor = INK_SOFT, labelsize = 13,\n)\n\n# --- Save -------------------------------------------------------------------\nsave(\"plot-$(THEME).png\", fig; px_per_unit = 2)\n"}