Tile Grid Map for Equal-Area Geographic Comparison — Makie.jl

A tile grid map represents geographic regions (states, countries, provinces) as equally-sized tiles — squares or hexagons — arranged to approximate their real-world geographic positions. Unlike choropleth maps where large-area regions dominate visually, every region receives identical visual weight, making tile grid maps ideal for per-capita or per-region comparisons where the statistic matters more than physical area. Tiles are colored by a data variable and labeled with region abbreviations for identification.

Tile Grid Map for Equal-Area Geographic Comparison rendered with Makie.jl

Renders

Julia source (Makie.jl)

# anyplot.ai
# map-tilegrid: Tile Grid Map for Equal-Area Geographic Comparison
# Library: makie 0.21.9 | Julia 1.11.9
# Quality: 91/100 | Created: 2026-09-05

using CairoMakie
using ColorSchemes
using Colors
using Random

Random.seed!(42)

# --- Theme tokens ------------------------------------------------------------
const THEME    = get(ENV, "ANYPLOT_THEME", "light")
const PAGE_BG  = THEME == "light" ? colorant"#FAF8F1" : colorant"#1A1A17"
const INK      = THEME == "light" ? colorant"#1A1A17" : colorant"#F0EFE8"
const INK_SOFT = THEME == "light" ? colorant"#4A4A44" : colorant"#B8B7B0"

# Continuous, single-polarity metric (share of electricity, %) -> imprint_seq
const ANYPLOT_SEQ = cgrad([colorant"#009E73", colorant"#4467A3"])
const TILE_LABEL  = colorant"#FAF8F1"  # constant across themes: sits on data color, not page bg
const TILE_OUTLINE = colorant"#1A1A17"  # constant across themes: text outline for legibility

# --- Data ----------------------------------------------------------------
# European countries laid out on an equal-area tile grid, approximating true
# geographic position (row 0 = north, col 0 = west). Renewable electricity
# share is a unipolar metric, so it uses the sequential Imprint colormap.
codes = [
    "IS", "NO", "SE", "FI",
    "IE", "UK", "DK", "EE",
    "NL", "DE", "CZ", "PL", "LV",
    "BE", "FR", "CH", "AT", "SK", "LT",
    "PT", "ES", "IT", "HU", "RO",
    "HR", "GR", "BG",
]
rows = [
    0, 0, 0, 0,
    1, 1, 1, 1,
    2, 2, 2, 2, 2,
    3, 3, 3, 3, 3, 3,
    4, 4, 4, 4, 4,
    5, 5, 5,
]
cols = [
    0, 3, 4, 5,
    0, 1, 4, 6,
    1, 3, 4, 5, 6,
    1, 2, 3, 4, 5, 6,
    0, 1, 3, 4, 5,
    3, 5, 6,
]
base_renewable_pct = [
    100.0, 98.0, 75.0, 55.0,
    40.0, 43.0, 65.0, 25.0,
    33.0, 46.0, 18.0, 17.0, 45.0,
    25.0, 27.0, 75.0, 78.0, 20.0, 30.0,
    61.0, 42.0, 35.0, 15.0, 42.0,
    40.0, 30.0, 20.0,
]
renewable_pct = clamp.(
    round.(base_renewable_pct .+ (rand(length(base_renewable_pct)) .- 0.5) .* 6, digits=1),
    0.0, 100.0,
)

n_cols = maximum(cols) + 1
n_rows = maximum(rows) + 1
value_min, value_max = extrema(renewable_pct)
norm_values = (renewable_pct .- value_min) ./ (value_max - value_min)
tile_colors = [get(ANYPLOT_SEQ, t) for t in norm_values]

tile_gap = 0.05
tile_rects = [
    Rect2f(c + tile_gap, -(r + 1 - tile_gap), 1 - 2tile_gap, 1 - 2tile_gap)
    for (r, c) in zip(rows, cols)
]
label_positions = [Point2f(c + 0.5, -(r + 0.5)) for (r, c) in zip(rows, cols)]

# Highlight the highest/lowest performers to give the color gradient an
# explicit focal point, rather than relying on the gradient alone.
max_idx = argmax(renewable_pct)
min_idx = argmin(renewable_pct)
stroke_colors = fill(PAGE_BG, length(tile_rects))
stroke_widths = fill(5.0, length(tile_rects))
stroke_colors[max_idx] = INK
stroke_colors[min_idx] = INK
stroke_widths[max_idx] = 6.0
stroke_widths[min_idx] = 6.0

# --- Plot ----------------------------------------------------------------
fig = Figure(
    size            = (1200, 1200),
    fontsize        = 14,
    backgroundcolor = PAGE_BG,
)

ax = Axis(
    fig[1, 1];
    title           = "map-tilegrid · julia · makie · anyplot.ai",
    titlesize       = 20,
    titlecolor      = INK,
    backgroundcolor = PAGE_BG,
    aspect          = DataAspect(),
)
hidedecorations!(ax)
hidespines!(ax)
xlims!(ax, -0.3, n_cols + 0.3)
ylims!(ax, -(n_rows + 0.3), 0.3)

poly!(ax, tile_rects; color = tile_colors, strokecolor = stroke_colors, strokewidth = stroke_widths)
text!(
    ax, label_positions;
    text        = codes,
    align       = (:center, :center),
    fontsize    = 17,
    color       = TILE_LABEL,
    strokecolor = TILE_OUTLINE,
    strokewidth = 1,
)
text!(
    ax, Point2f(n_cols / 2, 0.15);
    text     = "Highest: $(codes[max_idx]) ($(renewable_pct[max_idx])%)   ·   Lowest: $(codes[min_idx]) ($(renewable_pct[min_idx])%)",
    align    = (:center, :center),
    fontsize = 13,
    color    = INK_SOFT,
)

Colorbar(
    fig[2, 1];
    colormap      = ANYPLOT_SEQ,
    limits        = (value_min, value_max),
    vertical      = false,
    flipaxis      = false,
    label         = "Renewable Energy Share (%)",
    labelcolor    = INK,
    labelsize     = 14,
    ticklabelsize = 12,
    ticklabelcolor = INK_SOFT,
    tickcolor     = INK_SOFT,
    height        = 40,
)
rowsize!(fig.layout, 1, Relative(0.88))
rowgap!(fig.layout, 18)

# --- Save ------------------------------------------------------------------
save("plot-$(THEME).png", fig; px_per_unit = 2)

Retrieve this implementation

Runnable source as JSON, for any HTTP client: https://api.anyplot.ai/specs/map-tilegrid/makie/code. Any spec id and library id listed in llms-full.txt fit the same URL shape; every URL below is complete and callable.

{
  "spec_id": "map-tilegrid",
  "language": "julia",
  "library": "makie",
  "page": "https://anyplot.ai/map-tilegrid/julia/makie",
  "hub": "https://anyplot.ai/map-tilegrid",
  "code_json": "https://api.anyplot.ai/specs/map-tilegrid/makie/code",
  "spec_json": "https://api.anyplot.ai/specs/map-tilegrid",
  "render_light_png": "https://storage.googleapis.com/anyplot-images/plots/map-tilegrid/julia/makie/plot-light.png",
  "render_dark_png": "https://storage.googleapis.com/anyplot-images/plots/map-tilegrid/julia/makie/plot-dark.png",
  "quality_score": 91.0,
  "license": "MIT",
  "guide": "https://anyplot.ai/llms.txt"
}

Part of Tile Grid Map for Equal-Area Geographic Comparison on anyplot.ai.

Other implementations