{"spec_id":"choropleth-basic","library":"makie","language":"julia","code":"# anyplot.ai\n# choropleth-basic: Choropleth Map with Regional Coloring\n# Library: makie 0.21.9 | Julia 1.11.9\n# Quality: 88/100 | Created: 2026-09-02\n\nusing CairoMakie\nusing Colors\nusing ColorSchemes\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 ELEVATED = THEME == \"light\" ? colorant\"#FFFDF6\" : colorant\"#242420\"\nconst INK      = THEME == \"light\" ? colorant\"#1A1A17\" : colorant\"#F0EFE8\"\nconst INK_SOFT = THEME == \"light\" ? colorant\"#4A4A44\" : colorant\"#B8B7B0\"\nconst MUTED    = THEME == \"light\" ? colorant\"#6B6A63\" : colorant\"#A8A79F\"\n# Data tiles keep the same green/blue fill in both themes, so the label ink\n# drawn on top of them must stay fixed too — it must NOT follow a\n# theme-adaptive chrome token like ELEVATED, which is for callout-box\n# backgrounds and correctly flips dark in dark mode (wrong here).\nconst DATA_TILE_INK = colorant\"#FFFDF6\"\n\n# Imprint sequential colormap — single-polarity continuous data\nconst IMPRINT_SEQ = cgrad([colorant\"#009E73\", colorant\"#4467A3\"])\n\n# --- Data: renewable-energy share by U.S. state (%) -------------------------\n# CairoMakie has no geographic-projection support in this runtime (no\n# GeoMakie / shapefile access), so states are laid out on a schematic\n# west-to-east, north-to-south grid instead of true polygon boundaries —\n# a standard \"tile grid map\" technique for choropleth-style regional\n# shading that needs no shapefile dependency. Each cell holds (col, row).\nconst STATE_GRID = Dict(\n    \"AK\" => (0, 0), \"ME\" => (11, 0),\n    \"WA\" => (1, 1), \"ID\" => (2, 1), \"MT\" => (3, 1), \"ND\" => (4, 1),\n    \"MN\" => (5, 1), \"WI\" => (6, 1), \"MI\" => (7, 1), \"NY\" => (9, 1),\n    \"VT\" => (10, 1), \"NH\" => (11, 1),\n    \"OR\" => (1, 2), \"NV\" => (2, 2), \"WY\" => (3, 2), \"SD\" => (4, 2),\n    \"IA\" => (5, 2), \"IL\" => (6, 2), \"IN\" => (7, 2), \"OH\" => (8, 2),\n    \"PA\" => (9, 2), \"MA\" => (10, 2), \"RI\" => (11, 2),\n    \"CA\" => (1, 3), \"UT\" => (2, 3), \"CO\" => (3, 3), \"NE\" => (4, 3),\n    \"MO\" => (5, 3), \"KY\" => (6, 3), \"WV\" => (7, 3), \"VA\" => (8, 3),\n    \"MD\" => (9, 3), \"NJ\" => (10, 3), \"CT\" => (11, 3),\n    \"AZ\" => (2, 4), \"NM\" => (3, 4), \"KS\" => (4, 4), \"AR\" => (5, 4),\n    \"TN\" => (6, 4), \"NC\" => (7, 4), \"SC\" => (8, 4), \"DE\" => (9, 4),\n    \"TX\" => (3, 5), \"OK\" => (4, 5), \"LA\" => (5, 5), \"MS\" => (6, 5),\n    \"AL\" => (7, 5), \"GA\" => (8, 5),\n    \"FL\" => (8, 6),\n    \"HI\" => (0, 7),\n)\n\nstates = sort(collect(keys(STATE_GRID)))\n\n# Illustrative/synthetic values (not sourced from real generation\n# statistics). A mild regional bias is layered on top of the random\n# baseline — Pacific/Mountain/Plains states lean higher (wind + hydro\n# capacity), a few coal-belt Southeast/Midwest states lean lower — so the\n# map reads as a plausible spatial pattern rather than pure noise.\nconst HIGH_RENEWABLE_STATES = Set([\"WA\", \"OR\", \"CA\", \"ID\", \"IA\", \"KS\", \"ND\", \"VT\", \"ME\", \"NH\"])\nconst LOW_RENEWABLE_STATES  = Set([\"WV\", \"KY\", \"IN\", \"OH\", \"MS\", \"AL\", \"LA\"])\n\nrenewable_share = Dict{String, Float64}()\nfor s in states\n    bias = s in HIGH_RENEWABLE_STATES ? 15.0 : (s in LOW_RENEWABLE_STATES ? -10.0 : 0.0)\n    renewable_share[s] = clamp(round(15 + 55 * rand() + bias, digits=1), 5.0, 92.0)\nend\n\n# A few states have not reported yet — rendered as muted \"no data\" tiles\nfor s in (\"MT\", \"SD\", \"WY\")\n    renewable_share[s] = NaN\nend\n\ndata_values = [v for v in values(renewable_share) if !isnan(v)]\nvmin, vmax = extrema(data_values)\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           = \"choropleth-basic · julia · makie · anyplot.ai\",\n    titlesize       = 20,\n    titlecolor      = INK,\n    backgroundcolor = PAGE_BG,\n    aspect          = DataAspect(),\n)\nhidedecorations!(ax)\nhidespines!(ax)\n\ntile = 0.86  # tile side length; the 0.14 gap reads as grid seams between states\n\nfor s in states\n    col, row = STATE_GRID[s]\n    x, y = Float64(col), -Float64(row)\n    v = renewable_share[s]\n    missing_data = isnan(v)\n    fill_color = missing_data ? MUTED : IMPRINT_SEQ[(v - vmin) / (vmax - vmin)]\n    # MUTED flips from medium-dark (light theme) to medium-light (dark theme),\n    # so the \"no data\" tile needs the opposite text tone from data tiles.\n    text_color = missing_data ? (THEME == \"light\" ? ELEVATED : colorant\"#1A1A17\") : DATA_TILE_INK\n\n    poly!(ax, Rect2f(x - tile / 2, y - tile / 2, tile, tile);\n          color = fill_color, strokewidth = 2, strokecolor = PAGE_BG)\n    text!(ax, Point2f(x, y); text = s, align = (:center, :center),\n          fontsize = 13, color = text_color)\nend\n\nColorbar(fig[1, 2];\n    limits         = (vmin, vmax),\n    colormap       = IMPRINT_SEQ,\n    label          = \"Renewable Energy Share (%)\",\n    labelcolor     = INK,\n    ticklabelcolor = INK_SOFT,\n    labelsize      = 14,\n    ticklabelsize  = 12,\n    width          = 20,\n)\ncolgap!(fig.layout, 20)\n\n# --- Save -------------------------------------------------------------------\nsave(\"plot-$(THEME).png\", fig; px_per_unit = 2)\n"}