{"spec_id":"dot-matrix-proportional","library":"makie","language":"julia","code":"# anyplot.ai\n# dot-matrix-proportional: Dot Matrix Chart for Proportional Counts\n# Library: makie 0.21.9 | Julia 1.11.9\n# Quality: 93/100 | Created: 2026-09-05\n\nusing CairoMakie\nusing Colors\nusing Random\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\"\n\n# Semantic anchors (see prompts/default-style-guide.md \"Semantic anchors\"):\n# sentiment/polarity categories map to green (positive) / red (negative) /\n# adaptive muted gray (neutral) rather than the canonical palette order.\nMUTED = THEME == \"light\" ? colorant\"#6B6A63\" : colorant\"#A8A79F\"\nCATEGORY_COLOR = Dict(\n    \"Satisfied\"    => colorant\"#009E73\",\n    \"Neutral\"      => MUTED,\n    \"Dissatisfied\" => colorant\"#AE3030\",\n)\n\n# --- Data: customer satisfaction survey, 300 respondents -----------------------\ncategories = [\"Satisfied\", \"Neutral\", \"Dissatisfied\"]\ncounts     = [168, 72, 60]\ntotal      = sum(counts)\n\nn_cols = 15\nn_rows = cld(total, n_cols)\n\ndot_category = String[]\nfor (cat, n) in zip(categories, counts)\n    append!(dot_category, fill(cat, n))\nend\n\ndot_x = Float64[]\ndot_y = Float64[]\nfor i in 0:(total - 1)\n    row = i ÷ n_cols\n    col = i % n_cols\n    push!(dot_x, col)\n    push!(dot_y, n_rows - 1 - row)  # row 0 (first filled) sits at the top\nend\n\n# --- Plot -----------------------------------------------------------------------\nfig = Figure(\n    resolution      = (1200, 1200),\n    fontsize        = 14,\n    backgroundcolor = PAGE_BG,\n)\n\nax = Axis(\n    fig[1, 1];\n    title            = \"dot-matrix-proportional · julia · makie · anyplot.ai\",\n    titlesize        = 30,\n    titlecolor       = INK,\n    subtitle         = \"$(total) survey respondents, one dot per person\",\n    subtitlesize     = 16,\n    subtitlecolor    = INK_SOFT,\n    backgroundcolor  = PAGE_BG,\n    aspect           = DataAspect(),\n)\nhidedecorations!(ax)\nhidespines!(ax)\n\nfor (i, cat) in enumerate(categories)\n    mask = dot_category .== cat\n    pct = round(100 * counts[i] / total; digits = 1)\n    scatter!(\n        ax, dot_x[mask], dot_y[mask];\n        color       = CATEGORY_COLOR[cat],\n        markersize  = 30,\n        strokewidth = 0,\n        label       = \"$cat — $(counts[i]) ($(pct)%)\",\n    )\nend\n\nLegend(\n    fig[1, 2], ax, \"Response\";\n    labelcolor      = INK,\n    titlecolor      = INK,\n    framevisible    = false,\n    backgroundcolor = PAGE_BG,\n    labelsize       = 16,\n    titlesize       = 18,\n)\n\ncolsize!(fig.layout, 1, Relative(0.78))\n\n# --- Save -------------------------------------------------------------------\nsave(\"plot-$(THEME).png\", fig; px_per_unit = 2)\n"}