{"spec_id":"waffle-basic","library":"makie","language":"julia","code":"# anyplot.ai\n# waffle-basic: Basic Waffle Chart\n# Library: makie 0.21.9 | Julia 1.11.9\n# Quality: 85/100 | Created: 2026-09-09\n\nusing CairoMakie\nusing Colors\n\n# --- Theme tokens ------------------------------------------------------------\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\"\nconst IMPRINT_PALETTE = [\n    colorant\"#009E73\",  # 1 — brand green, ALWAYS first series\n    colorant\"#C475FD\",  # 2 — lavender\n    colorant\"#4467A3\",  # 3 — blue\n    colorant\"#BD8233\",  # 4 — ochre\n    colorant\"#AE3030\",  # 5 — matte red\n]\n\n# --- Data: household budget allocation, 100 squares = 100% -------------------\ncategories = [\"Housing\", \"Food\", \"Transportation\", \"Savings\", \"Entertainment\"]\npercentages = [32, 22, 18, 16, 12]\nfocal_idx = argmax(percentages)\n\ngrid_size = 10\ncell_categories = Vector{Int}(undef, grid_size^2)\ncursor = 1\nfor (cat_idx, count) in enumerate(percentages)\n    cell_categories[cursor:(cursor + count - 1)] .= cat_idx\n    global cursor += count\nend\n\nsquare_gap = 0.12\nsquare_side = 1.0 - square_gap\nsquares = Vector{Rect2{Float64}}(undef, grid_size^2)\ncell_colors = Vector{eltype(IMPRINT_PALETTE)}(undef, grid_size^2)\nfor i in 1:(grid_size^2)\n    row = (i - 1) ÷ grid_size          # 0 = top row\n    col = (i - 1) % grid_size\n    x = col + square_gap / 2\n    y = (grid_size - 1 - row) + square_gap / 2\n    squares[i] = Rect2(Float64(x), Float64(y), square_side, square_side)\n    cell_colors[i] = IMPRINT_PALETTE[cell_categories[i]]\nend\n\nfocal_mask    = cell_categories .== focal_idx\nsquares_rest  = squares[.!focal_mask]\ncolors_rest   = cell_colors[.!focal_mask]\nsquares_focal = squares[focal_mask]\ncolors_focal  = cell_colors[focal_mask]\n\n# --- Plot ----------------------------------------------------------------\ntitle_text    = \"waffle-basic · julia · makie · anyplot.ai\"\nsubtitle_text = \"$(categories[focal_idx]) leads the budget at $(percentages[focal_idx])%\"\n\ncanvas_side     = 1200\ntitle_height    = 92\nsubtitle_height = 40\nlegend_height   = 70\nrow_gap         = 16\nsquare_side_px  = canvas_side - title_height - subtitle_height - legend_height - 3 * row_gap\n\nfig = Figure(\n    size            = (canvas_side, canvas_side),\n    fontsize        = 16,\n    backgroundcolor = PAGE_BG,\n)\n\nLabel(\n    fig[1, 1], title_text;\n    fontsize = 38, color = INK, font = :bold, halign = :center,\n)\n\nLabel(\n    fig[2, 1], subtitle_text;\n    fontsize = 18, color = INK_SOFT, halign = :center,\n)\n\nax = Axis(\n    fig[3, 1];\n    aspect          = DataAspect(),\n    backgroundcolor = PAGE_BG,\n)\nhidespines!(ax)\nhidedecorations!(ax)\n\n# Focal category (largest share) gets an ink-colored outline to anchor the\n# eye and reinforce the storytelling callout above; every other square keeps\n# the neutral background-colored gap stroke.\npoly!(ax, squares_rest; color = colors_rest, strokewidth = 3, strokecolor = PAGE_BG)\npoly!(ax, squares_focal; color = colors_focal, strokewidth = 5, strokecolor = INK)\nxlims!(ax, 0, grid_size)\nylims!(ax, 0, grid_size)\n\nlegend_labels = [\"$(categories[i]) ($(percentages[i])%)\" for i in eachindex(categories)]\nlegend_elements = [PolyElement(color = IMPRINT_PALETTE[i], strokewidth = 0) for i in eachindex(categories)]\nLegend(\n    fig[4, 1], legend_elements, legend_labels;\n    orientation     = :horizontal,\n    framevisible    = false,\n    backgroundcolor = :transparent,\n    labelcolor      = INK,\n    labelsize       = 18,\n    patchsize       = (22, 22),\n    colgap          = 18,\n    halign          = :center,\n)\n\nrowsize!(fig.layout, 1, Fixed(title_height))\nrowsize!(fig.layout, 2, Fixed(subtitle_height))\nrowsize!(fig.layout, 3, Fixed(square_side_px))\nrowsize!(fig.layout, 4, Fixed(legend_height))\ncolsize!(fig.layout, 1, Fixed(square_side_px))\nrowgap!(fig.layout, row_gap)\n\n# --- Save ------------------------------------------------------------------\nsave(\"plot-$(THEME).png\", fig; px_per_unit = 2)\n"}