Skip to content

Commit 1d24d1a

Browse files
feat(seaborn): implement choropleth-basic (#3105)
## Implementation: `choropleth-basic` - seaborn Implements the **seaborn** version of `choropleth-basic`. **File:** `plots/choropleth-basic/implementations/seaborn.py` **Parent Issue:** #3069 --- :robot: *[impl-generate workflow](https://github.com/MarkusNeusinger/pyplots/actions/runs/20620322599)* --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
1 parent 4c41d1d commit 1d24d1a

2 files changed

Lines changed: 226 additions & 0 deletions

File tree

Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
""" pyplots.ai
2+
choropleth-basic: Choropleth Map with Regional Coloring
3+
Library: seaborn 0.13.2 | Python 3.13.11
4+
Quality: 88/100 | Created: 2025-12-31
5+
"""
6+
7+
import matplotlib.patches as mpatches
8+
import matplotlib.pyplot as plt
9+
import numpy as np
10+
import pandas as pd
11+
import seaborn as sns
12+
13+
14+
# Data: US states tile grid map with economic data (GDP growth rate %)
15+
# Tile grid maps are a recognized cartogram technique that ensures equal visual weight per region
16+
np.random.seed(42)
17+
18+
# State data with grid positions (row, col) approximating US map layout
19+
# Values represent GDP growth rate (%) - None indicates missing data
20+
states_data = {
21+
# Row 0 (top - Pacific Northwest, Northern states)
22+
"WA": (0, 1, 3.2),
23+
"MT": (0, 3, 1.8),
24+
"ND": (0, 5, 2.1),
25+
"MN": (0, 6, 2.9),
26+
"WI": (0, 7, 2.3),
27+
"MI": (0, 8, 1.9),
28+
"NY": (0, 10, 3.5),
29+
"VT": (0, 11, 1.5),
30+
"ME": (0, 12, 1.2),
31+
# Row 1
32+
"OR": (1, 1, 2.8),
33+
"ID": (1, 2, 3.1),
34+
"WY": (1, 3, 0.9),
35+
"SD": (1, 5, 1.7),
36+
"IA": (1, 6, 2.0),
37+
"IL": (1, 7, 2.5),
38+
"IN": (1, 8, 2.2),
39+
"OH": (1, 9, 1.8),
40+
"PA": (1, 10, 2.1),
41+
"MA": (1, 11, 3.8),
42+
"NH": (1, 12, 2.4),
43+
# Row 2
44+
"NV": (2, 1, 4.1),
45+
"UT": (2, 2, 4.5),
46+
"CO": (2, 3, 3.9),
47+
"NE": (2, 5, 1.6),
48+
"KS": (2, 6, 1.4),
49+
"MO": (2, 7, 1.9),
50+
"KY": (2, 8, 2.0),
51+
"WV": (2, 9, 0.5),
52+
"VA": (2, 10, 3.2),
53+
"MD": (2, 11, 2.8),
54+
"NJ": (2, 12, 2.6),
55+
# Row 3
56+
"CA": (3, 1, 3.7),
57+
"AZ": (3, 2, 4.2),
58+
"NM": (3, 3, 1.3),
59+
"OK": (3, 5, 1.1),
60+
"AR": (3, 6, 1.5),
61+
"TN": (3, 7, 3.0),
62+
"NC": (3, 9, 3.4),
63+
"SC": (3, 10, 2.7),
64+
"DE": (3, 11, 2.3),
65+
"CT": (3, 12, 2.9),
66+
# Row 4 (bottom - Southern states)
67+
"TX": (4, 3, 3.6),
68+
"LA": (4, 5, 0.8),
69+
"MS": (4, 6, 0.6),
70+
"AL": (4, 7, 1.7),
71+
"GA": (4, 8, 3.3),
72+
"FL": (4, 10, 3.8),
73+
"RI": (4, 12, 2.0),
74+
# Missing data examples (show as gray/hatched pattern per spec)
75+
"PR": (4, 13, None), # Puerto Rico - no data
76+
# Alaska and Hawaii (offset)
77+
"AK": (5, 0, 0.4),
78+
"HI": (5, 2, 2.5),
79+
"DC": (3, 13, None), # DC - no data available
80+
}
81+
82+
# Create DataFrame
83+
rows = []
84+
for state, (r, c, val) in states_data.items():
85+
rows.append({"state": state, "row": r, "col": c, "gdp_growth": val})
86+
df = pd.DataFrame(rows)
87+
88+
# Create grid matrix for heatmap (6 rows x 14 cols)
89+
n_rows, n_cols = 6, 14
90+
grid = np.full((n_rows, n_cols), np.nan)
91+
state_labels = np.full((n_rows, n_cols), "", dtype=object)
92+
missing_mask = np.zeros((n_rows, n_cols), dtype=bool)
93+
94+
for _, row in df.iterrows():
95+
r, c = int(row["row"]), int(row["col"])
96+
if row["gdp_growth"] is not None and not pd.isna(row["gdp_growth"]):
97+
grid[r, c] = row["gdp_growth"]
98+
else:
99+
missing_mask[r, c] = True # Mark as missing data
100+
state_labels[r, c] = row["state"]
101+
102+
# Set up seaborn styling
103+
sns.set_theme(style="white", context="talk", font_scale=1.2)
104+
105+
# Create figure with appropriate size for 4800x2700 output
106+
fig, ax = plt.subplots(figsize=(16, 9))
107+
108+
# Create heatmap using seaborn with masked values for empty cells
109+
empty_mask = np.isnan(grid) & ~missing_mask # True for truly empty cells (no state)
110+
heatmap = sns.heatmap(
111+
grid,
112+
mask=empty_mask,
113+
cmap="YlGnBu",
114+
annot=False, # We'll add custom annotations
115+
cbar=True,
116+
cbar_kws={"label": "GDP Growth Rate (%)", "shrink": 0.7, "aspect": 20, "pad": 0.02},
117+
linewidths=1.5, # Reduced from 3 to be less overwhelming
118+
linecolor="white",
119+
square=True,
120+
vmin=0,
121+
vmax=5,
122+
ax=ax,
123+
)
124+
125+
# Add gray cells for missing data with hatching pattern
126+
for i in range(n_rows):
127+
for j in range(n_cols):
128+
if missing_mask[i, j]:
129+
# Draw gray rectangle with hatching for missing data
130+
rect = mpatches.Rectangle(
131+
(j, i), 1, 1, fill=True, facecolor="#d0d0d0", edgecolor="white", linewidth=1.5, hatch="///", zorder=2
132+
)
133+
ax.add_patch(rect)
134+
135+
# Customize colorbar
136+
cbar = heatmap.collections[0].colorbar
137+
cbar.ax.tick_params(labelsize=18)
138+
cbar.set_label("GDP Growth Rate (%)", fontsize=20, labelpad=10)
139+
140+
# Add state code and value annotations
141+
for i in range(n_rows):
142+
for j in range(n_cols):
143+
if state_labels[i, j]: # If there's a state here
144+
# State code (larger, bold)
145+
ax.text(
146+
j + 0.5,
147+
i + 0.35,
148+
state_labels[i, j],
149+
ha="center",
150+
va="center",
151+
fontsize=20,
152+
fontweight="bold",
153+
color="#1a1a1a" if not missing_mask[i, j] else "#666666",
154+
)
155+
# Value or "N/A" for missing data (increased from 13pt to 16pt)
156+
if not missing_mask[i, j] and not np.isnan(grid[i, j]):
157+
ax.text(
158+
j + 0.5,
159+
i + 0.7,
160+
f"{grid[i, j]:.1f}%",
161+
ha="center",
162+
va="center",
163+
fontsize=16,
164+
color="#333333",
165+
fontweight="medium",
166+
)
167+
else:
168+
ax.text(
169+
j + 0.5, i + 0.7, "N/A", ha="center", va="center", fontsize=16, color="#888888", fontstyle="italic"
170+
)
171+
172+
# Styling
173+
ax.set_title("choropleth-basic · seaborn · pyplots.ai", fontsize=26, pad=20, fontweight="bold")
174+
175+
# Remove axis labels and ticks (tile grid doesn't need them)
176+
ax.set_xticks([])
177+
ax.set_yticks([])
178+
ax.set_xlabel("")
179+
ax.set_ylabel("")
180+
181+
# Add legend for missing data
182+
missing_patch = mpatches.Patch(facecolor="#d0d0d0", edgecolor="white", hatch="///", label="No Data Available")
183+
ax.legend(handles=[missing_patch], loc="lower left", fontsize=16, framealpha=0.9)
184+
185+
# Add subtitle explaining the visualization
186+
ax.text(
187+
0.5,
188+
-0.06,
189+
"US States GDP Growth Rate (%) — Tile Grid Choropleth Map",
190+
ha="center",
191+
va="top",
192+
fontsize=18,
193+
color="#555555",
194+
transform=ax.transAxes,
195+
)
196+
197+
plt.tight_layout()
198+
plt.savefig("plot.png", dpi=300, bbox_inches="tight")
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
library: seaborn
2+
specification_id: choropleth-basic
3+
created: '2025-12-31T13:54:42Z'
4+
updated: '2025-12-31T15:12:09Z'
5+
generated_by: claude-opus-4-5-20251101
6+
workflow_run: 20620322599
7+
issue: 3069
8+
python_version: 3.13.11
9+
library_version: 0.13.2
10+
preview_url: https://storage.googleapis.com/pyplots-images/plots/choropleth-basic/seaborn/plot.png
11+
preview_thumb: https://storage.googleapis.com/pyplots-images/plots/choropleth-basic/seaborn/plot_thumb.png
12+
preview_html: null
13+
quality_score: 88
14+
review:
15+
strengths:
16+
- Excellent creative solution using tile grid cartogram approach for choropleth
17+
visualization
18+
- Clean, readable layout with well-sized state labels and values
19+
- Good use of seaborn heatmap function with appropriate colormap
20+
- Realistic economic data scenario with plausible GDP growth rates
21+
- Good colorblind-friendly palette choice (YlGnBu)
22+
- Well-structured code following KISS principles
23+
weaknesses:
24+
- Title format includes extra descriptive text instead of strictly following spec-id
25+
format
26+
- Missing data handling (gray hatched cells) not visible in rendered image
27+
- Subtitle text could be slightly larger for better readability
28+
- Could show wider range of values to demonstrate more color scale variation

0 commit comments

Comments
 (0)