Choropleth Map with Regional Coloring — Seaborn

A choropleth map visualizes data by shading geographic regions (countries, states, or counties) according to a measured variable. This technique is ideal for showing regional patterns and spatial distributions, making it easy to identify areas with high or low values at a glance. The color intensity represents the data magnitude, creating an intuitive way to understand geographic variation.

Choropleth Map with Regional Coloring rendered with Seaborn

Python source (Seaborn)

""" anyplot.ai
choropleth-basic: Choropleth Map with Regional Coloring
Library: seaborn 0.13.2 | Python 3.13.13
Quality: 82/100 | Updated: 2026-05-15
"""

import matplotlib.patches as mpatches
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import seaborn as sns


# Data: US states tile grid map with economic data (GDP growth rate %)
# Tile grid maps are a recognized cartogram technique that ensures equal visual weight per region
np.random.seed(42)

# State data with grid positions (row, col) approximating US map layout
# Values represent GDP growth rate (%) - None indicates missing data
states_data = {
    # Row 0 (top - Pacific Northwest, Northern states)
    "WA": (0, 1, 3.2),
    "MT": (0, 3, 1.8),
    "ND": (0, 5, 2.1),
    "MN": (0, 6, 2.9),
    "WI": (0, 7, 2.3),
    "MI": (0, 8, 1.9),
    "NY": (0, 10, 3.5),
    "VT": (0, 11, 1.5),
    "ME": (0, 12, 1.2),
    # Row 1
    "OR": (1, 1, 2.8),
    "ID": (1, 2, 3.1),
    "WY": (1, 3, 0.9),
    "SD": (1, 5, 1.7),
    "IA": (1, 6, 2.0),
    "IL": (1, 7, 2.5),
    "IN": (1, 8, 2.2),
    "OH": (1, 9, 1.8),
    "PA": (1, 10, 2.1),
    "MA": (1, 11, 3.8),
    "NH": (1, 12, 2.4),
    # Row 2
    "NV": (2, 1, 4.1),
    "UT": (2, 2, 4.5),
    "CO": (2, 3, 3.9),
    "NE": (2, 5, 1.6),
    "KS": (2, 6, 1.4),
    "MO": (2, 7, 1.9),
    "KY": (2, 8, 2.0),
    "WV": (2, 9, 0.5),
    "VA": (2, 10, 3.2),
    "MD": (2, 11, 2.8),
    "NJ": (2, 12, 2.6),
    # Row 3
    "CA": (3, 1, 3.7),
    "AZ": (3, 2, 4.2),
    "NM": (3, 3, 1.3),
    "OK": (3, 5, 1.1),
    "AR": (3, 6, 1.5),
    "TN": (3, 7, 3.0),
    "NC": (3, 9, 3.4),
    "SC": (3, 10, 2.7),
    "DE": (3, 11, 2.3),
    "CT": (3, 12, 2.9),
    # Row 4 (bottom - Southern states)
    "TX": (4, 3, 3.6),
    "LA": (4, 5, 0.8),
    "MS": (4, 6, 0.6),
    "AL": (4, 7, 1.7),
    "GA": (4, 8, 3.3),
    "FL": (4, 10, 3.8),
    "RI": (4, 12, 2.0),
    # Missing data examples (show as gray/hatched pattern per spec)
    "PR": (4, 13, None),  # Puerto Rico - no data
    # Alaska and Hawaii (offset)
    "AK": (5, 0, 0.4),
    "HI": (5, 2, 2.5),
    "DC": (3, 13, None),  # DC - no data available
}

# Create DataFrame
rows = []
for state, (r, c, val) in states_data.items():
    rows.append({"state": state, "row": r, "col": c, "gdp_growth": val})
df = pd.DataFrame(rows)

# Create grid matrix for heatmap (6 rows x 14 cols)
n_rows, n_cols = 6, 14
grid = np.full((n_rows, n_cols), np.nan)
state_labels = np.full((n_rows, n_cols), "", dtype=object)
missing_mask = np.zeros((n_rows, n_cols), dtype=bool)

for _, row in df.iterrows():
    r, c = int(row["row"]), int(row["col"])
    if row["gdp_growth"] is not None and not pd.isna(row["gdp_growth"]):
        grid[r, c] = row["gdp_growth"]
    else:
        missing_mask[r, c] = True  # Mark as missing data
    state_labels[r, c] = row["state"]

# Set up seaborn styling
sns.set_theme(style="white", context="talk", font_scale=1.2)

# Create figure with appropriate size for 4800x2700 output
fig, ax = plt.subplots(figsize=(16, 9))

# Create heatmap using seaborn with masked values for empty cells
empty_mask = np.isnan(grid) & ~missing_mask  # True for truly empty cells (no state)
heatmap = sns.heatmap(
    grid,
    mask=empty_mask,
    cmap="YlGnBu",
    annot=False,  # We'll add custom annotations
    cbar=True,
    cbar_kws={"label": "GDP Growth Rate (%)", "shrink": 0.7, "aspect": 20, "pad": 0.02},
    linewidths=1.5,  # Reduced from 3 to be less overwhelming
    linecolor="white",
    square=True,
    vmin=0,
    vmax=5,
    ax=ax,
)

# Add gray cells for missing data with hatching pattern
for i in range(n_rows):
    for j in range(n_cols):
        if missing_mask[i, j]:
            # Draw gray rectangle with hatching for missing data
            rect = mpatches.Rectangle(
                (j, i), 1, 1, fill=True, facecolor="#d0d0d0", edgecolor="white", linewidth=1.5, hatch="///", zorder=2
            )
            ax.add_patch(rect)

# Customize colorbar
cbar = heatmap.collections[0].colorbar
cbar.ax.tick_params(labelsize=18)
cbar.set_label("GDP Growth Rate (%)", fontsize=20, labelpad=10)

# Add state code and value annotations
for i in range(n_rows):
    for j in range(n_cols):
        if state_labels[i, j]:  # If there's a state here
            # State code (larger, bold)
            ax.text(
                j + 0.5,
                i + 0.35,
                state_labels[i, j],
                ha="center",
                va="center",
                fontsize=20,
                fontweight="bold",
                color="#1a1a1a" if not missing_mask[i, j] else "#666666",
            )
            # Value or "N/A" for missing data (increased from 13pt to 16pt)
            if not missing_mask[i, j] and not np.isnan(grid[i, j]):
                ax.text(
                    j + 0.5,
                    i + 0.7,
                    f"{grid[i, j]:.1f}%",
                    ha="center",
                    va="center",
                    fontsize=16,
                    color="#333333",
                    fontweight="medium",
                )
            else:
                ax.text(
                    j + 0.5, i + 0.7, "N/A", ha="center", va="center", fontsize=16, color="#888888", fontstyle="italic"
                )

# Styling
ax.set_title("choropleth-basic · seaborn · pyplots.ai", fontsize=26, pad=20, fontweight="bold")

# Remove axis labels and ticks (tile grid doesn't need them)
ax.set_xticks([])
ax.set_yticks([])
ax.set_xlabel("")
ax.set_ylabel("")

# Add legend for missing data
missing_patch = mpatches.Patch(facecolor="#d0d0d0", edgecolor="white", hatch="///", label="No Data Available")
ax.legend(handles=[missing_patch], loc="lower left", fontsize=16, framealpha=0.9)

# Add subtitle explaining the visualization
ax.text(
    0.5,
    -0.06,
    "US States GDP Growth Rate (%) — Tile Grid Choropleth Map",
    ha="center",
    va="top",
    fontsize=18,
    color="#555555",
    transform=ax.transAxes,
)

plt.tight_layout()
plt.savefig("plot.png", dpi=300, bbox_inches="tight")

Part of Choropleth Map with Regional Coloring on anyplot.ai.

Other implementations