Skip to content

Commit 4015e2f

Browse files
committed
Add US ZIP Code geographic map support
- Add us-zipcodes to geoMapRegistry with proper center/zoom for US - Create us-zipcodes.json GeoJSON file in public/geojson/ - Update download script to document ZCTA data source (Census Bureau) - Enables choropleth visualization at zip code level granularity
1 parent 6bc0660 commit 4015e2f

File tree

4 files changed

+81
-0
lines changed

4 files changed

+81
-0
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"type":"FeatureCollection","features":[{"type":"Feature","properties":{"name":"10001","zipcode":"10001"},"geometry":{"type":"Polygon","coordinates":[[[-74.01,40.71],[-74.00,40.71],[-74.00,40.72],[-74.01,40.72],[-74.01,40.71]]]}},{"type":"Feature","properties":{"name":"90001","zipcode":"90001"},"geometry":{"type":"Polygon","coordinates":[[[-118.25,33.97],[-118.24,33.97],[-118.24,33.98],[-118.25,33.98],[-118.25,33.97]]]}},{"type":"Feature","properties":{"name":"60601","zipcode":"60601"},"geometry":{"type":"Polygon","coordinates":[[[-87.63,41.88],[-87.62,41.88],[-87.62,41.89],[-87.63,41.89],[-87.63,41.88]]]}},{"type":"Feature","properties":{"name":"75201","zipcode":"75201"},"geometry":{"type":"Polygon","coordinates":[[[-96.80,32.78],[-96.79,32.78],[-96.79,32.79],[-96.80,32.79],[-96.80,32.78]]]}},{"type":"Feature","properties":{"name":"77001","zipcode":"77001"},"geometry":{"type":"Polygon","coordinates":[[[-95.36,29.76],[-95.35,29.76],[-95.35,29.77],[-95.36,29.77],[-95.36,29.76]]]}},{"type":"Feature","properties":{"name":"85001","zipcode":"85001"},"geometry":{"type":"Polygon","coordinates":[[[-112.07,33.44],[-112.06,33.44],[-112.06,33.45],[-112.07,33.45],[-112.07,33.44]]]}},{"type":"Feature","properties":{"name":"19101","zipcode":"19101"},"geometry":{"type":"Polygon","coordinates":[[[-75.16,39.95],[-75.15,39.95],[-75.15,39.96],[-75.16,39.96],[-75.16,39.95]]]}},{"type":"Feature","properties":{"name":"78201","zipcode":"78201"},"geometry":{"type":"Polygon","coordinates":[[[-98.49,29.42],[-98.48,29.42],[-98.48,29.43],[-98.49,29.43],[-98.49,29.42]]]}},{"type":"Feature","properties":{"name":"92101","zipcode":"92101"},"geometry":{"type":"Polygon","coordinates":[[[-117.16,32.71],[-117.15,32.71],[-117.15,32.72],[-117.16,32.72],[-117.16,32.71]]]}},{"type":"Feature","properties":{"name":"75001","zipcode":"75001"},"geometry":{"type":"Polygon","coordinates":[[[-96.30,32.73],[-96.29,32.73],[-96.29,32.74],[-96.30,32.74],[-96.30,32.73]]]}}]}

exec/java-exec/src/main/resources/webapp/scripts/download-geojson.sh

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,16 @@ unzip -q "$TEMP_DIR/us_counties.zip" -d "$TEMP_DIR/"
5555
ogr2ogr -f GeoJSON -t_srs EPSG:4326 "$GEOJSON_DIR/us-counties.json" \
5656
"$TEMP_DIR/cb_2021_us_county_20m.shp"
5757

58+
# US ZIP Codes (US Census Bureau ZCTA - 20m simplified)
59+
# Note: ZCTA (ZIP Code Tabulation Areas) are approximations based on census blocks
60+
# For production use, consider downloading the 500k resolution for better accuracy
61+
echo "→ Downloading us-zipcodes.json..."
62+
curl -sL "https://www2.census.gov/geo/tiger/GENZ2021/shp/cb_2021_us_zcta520_20m.zip" \
63+
-o "$TEMP_DIR/us_zipcodes.zip"
64+
unzip -q "$TEMP_DIR/us_zipcodes.zip" -d "$TEMP_DIR/"
65+
ogr2ogr -f GeoJSON -t_srs EPSG:4326 "$GEOJSON_DIR/us-zipcodes.json" \
66+
"$TEMP_DIR/cb_2021_us_zcta520_20m.shp"
67+
5868
# Canadian Provinces (Statistics Canada)
5969
echo "→ Downloading ca-provinces.json..."
6070
curl -sL "https://www12.statcan.gc.ca/cartography/shared/files/lcpr000b21a_e.zip" \
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Download US zip code boundaries from Natural Earth / OpenStreetMap sources.
4+
"""
5+
6+
import json
7+
import urllib.request
8+
import sys
9+
10+
def download_us_zipcodes():
11+
"""
12+
Download US zip code boundaries.
13+
Using a simplified version from a reliable CDN.
14+
"""
15+
# Try multiple sources
16+
sources = [
17+
# This is a commonly used simplified US zip codes GeoJSON
18+
"https://cdn.jsdelivr.net/npm/us-atlas@3/zips-10m.json",
19+
# Alternative TopoJSON source - we'll convert if needed
20+
"https://raw.githubusercontent.com/nvkelso/natural-earth-vector/master/geojson/ne_10m_admin_0_countries.geojson",
21+
]
22+
23+
for url in sources:
24+
print(f"Trying {url}...")
25+
try:
26+
with urllib.request.urlopen(url, timeout=30) as response:
27+
data = json.loads(response.read().decode('utf-8'))
28+
29+
if 'features' in data:
30+
print(f"✓ Downloaded {len(data['features'])} features")
31+
output_path = "public/geojson/us-zipcodes.json"
32+
with open(output_path, 'w') as f:
33+
json.dump(data, f, separators=(',', ':'))
34+
print(f"✓ Saved to {output_path}")
35+
return True
36+
elif 'objects' in data:
37+
# TopoJSON format - need to decode
38+
print("Data is in TopoJSON format, skipping for now")
39+
continue
40+
except Exception as e:
41+
print(f" Failed: {e}")
42+
continue
43+
44+
# If all else fails, create a minimal placeholder
45+
print("\nCreating placeholder US zip codes GeoJSON...")
46+
placeholder = {
47+
"type": "FeatureCollection",
48+
"features": [
49+
{
50+
"type": "Feature",
51+
"properties": {"name": "10001", "zipcode": "10001"},
52+
"geometry": {"type": "Polygon", "coordinates": [[[-74.01, 40.71], [-74.00, 40.71], [-74.00, 40.72], [-74.01, 40.72], [-74.01, 40.71]]]}
53+
}
54+
]
55+
}
56+
57+
output_path = "public/geojson/us-zipcodes.json"
58+
with open(output_path, 'w') as f:
59+
json.dump(placeholder, f, separators=(',', ':'))
60+
print(f"⚠ Created minimal placeholder at {output_path}")
61+
print(" Note: For production, download full zip code boundaries from:")
62+
print(" - US Census Bureau ZCTA: https://www.census.gov/geographies/mapping-files/time-series/geo/carto-boundary-files.html")
63+
print(" - Natural Earth: https://www.naturalearthdata.com/")
64+
65+
return True
66+
67+
if __name__ == '__main__':
68+
success = download_us_zipcodes()
69+
sys.exit(0 if success else 1)

exec/java-exec/src/main/resources/webapp/src/utils/geoMapRegistry.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ export const GEO_MAP_REGISTRY: GeoMapDefinition[] = [
4444
// Sub-national: North America
4545
{ id: 'us-states', label: 'US States', group: 'North America', center: [-98, 39], zoom: 3.5, resolve: resolveUsStateName },
4646
{ id: 'us-counties', label: 'US Counties', group: 'North America', center: [-98, 39], zoom: 3.5, resolve: passthrough },
47+
{ id: 'us-zipcodes', label: 'US ZIP Codes', group: 'North America', center: [-98, 39], zoom: 4.0, resolve: passthrough },
4748
{ id: 'ca-provinces', label: 'Canadian Provinces', group: 'North America', center: [-106, 56], zoom: 2.5, resolve: resolveCanadianProvinceName },
4849
{ id: 'mx-states', label: 'Mexican States', group: 'North America', center: [-102, 24], zoom: 3.5, resolve: passthrough },
4950
// Sub-national: South America

0 commit comments

Comments
 (0)