open-navigator / web_docs /docs /data-sources /census-shapefiles.md
jcbowyer's picture
Clean HuggingFace deployment without binary files
e59d91d
|
Raw
History Blame Contribute Delete
10.3 kB
---
sidebar_position: 5
---
# Census Bureau Shapefiles
Geographic boundary data from the U.S. Census Bureau TIGER/Line program.
## Overview
The Census Bureau provides comprehensive geographic boundary files (shapefiles) for all U.S. administrative divisions. These are essential for mapping, spatial analysis, and geographic visualization.
**Data Source:** [U.S. Census Bureau TIGER/Line Files](https://www.census.gov/geographies/mapping-files/time-series/geo/tiger-line-file.html)
**Update Frequency:** Annual (typically released in summer)
**Latest Vintage:** 2023
## Available Boundary Types
### 1. States
- **File:** `cb_{year}_us_state_500k.zip`
- **Features:** 50 states + DC + territories (56 total)
- **Use Cases:** State-level aggregation, choropleth maps, jurisdiction lookup
- **Size:** ~3 MB
### 2. Counties
- **File:** `cb_{year}_us_county_500k.zip`
- **Features:** 3,143 counties and county equivalents
- **Use Cases:** County-level analysis, regional mapping, jurisdiction boundaries
- **Size:** ~15 MB
### 3. ZIP Code Tabulation Areas (ZCTAs)
- **File:** `cb_{year}_us_zcta520_500k.zip`
- **Features:** ~33,000 ZIP Code Tabulation Areas
- **Use Cases:** Postal code mapping, demographic analysis, service area definition
- **Size:** ~350 MB
- **Note:** ZCTAs are statistical approximations of ZIP codes, not exact postal routes
## Cartographic vs. Full TIGER Files
We use **Cartographic Boundary Files** (cb_* prefix) instead of full TIGER/Line files because:
| Feature | Cartographic (cb_) | Full TIGER (tl_) |
|---------|-------------------|------------------|
| **Detail** | Simplified 1:500k | High detail 1:100k |
| **File Size** | Smaller (faster downloads) | Larger (slower) |
| **Rendering** | Faster (optimized for maps) | Slower |
| **Water Boundaries** | Clipped at shoreline | Include water features |
| **Use Case** | Web mapping, visualization | Detailed GIS analysis |
**Recommendation:** Use cartographic files for Open Navigator's web-based mapping.
## Installation & Setup
### Prerequisites
```bash
# Shapefile processing requires geopandas
pip install geopandas pyogrio
```
### Download Script
```bash
# Download all shapefiles for 2023
python scripts/datasources/census/download_shapefiles.py --year 2023
# Download only states and counties
python scripts/datasources/census/download_shapefiles.py --year 2023 --types states counties
# Download and extract automatically
python scripts/datasources/census/download_shapefiles.py --year 2023 --extract
# Download only ZIP codes
python scripts/datasources/census/download_shapefiles.py --year 2023 --types zcta
```
## Data Storage
Downloaded shapefiles are cached in:
```
data/cache/census/shapefiles/{year}/
├── cb_2023_us_state_500k.zip
├── cb_2023_us_county_500k.zip
└── cb_2023_us_zcta520_500k.zip
```
Extracted files (if `--extract` used):
```
data/cache/census/shapefiles/{year}/
├── cb_2023_us_state_500k/
│ ├── cb_2023_us_state_500k.shp # Geometry
│ ├── cb_2023_us_state_500k.shx # Shape index
│ ├── cb_2023_us_state_500k.dbf # Attributes
│ ├── cb_2023_us_state_500k.prj # Projection
│ └── cb_2023_us_state_500k.xml # Metadata
├── cb_2023_us_county_500k/
└── cb_2023_us_zcta520_500k/
```
## Loading Shapefiles
### GeoPandas (Recommended)
```python
import geopandas as gpd
from pathlib import Path
# Load from ZIP (no extraction needed!)
states = gpd.read_file("data/cache/census/shapefiles/2023/cb_2023_us_state_500k.zip")
# Or from extracted directory
states = gpd.read_file("data/cache/census/shapefiles/2023/cb_2023_us_state_500k/cb_2023_us_state_500k.shp")
# View data
print(states.head())
print(f"Total states: {len(states)}")
print(f"CRS: {states.crs}") # Should be EPSG:4269 (NAD83)
```
### Key Attributes
#### States
- `STATEFP` - State FIPS code (2 digits)
- `STUSPS` - State postal abbreviation (2 letters)
- `NAME` - State name
- `ALAND` - Land area (square meters)
- `AWATER` - Water area (square meters)
#### Counties
- `STATEFP` - State FIPS code
- `COUNTYFP` - County FIPS code (3 digits)
- `GEOID` - Combined state+county FIPS (5 digits)
- `NAME` - County name
- `NAMELSAD` - Full name with legal/statistical designation
#### ZCTAs
- `ZCTA5CE20` - 5-digit ZCTA code
- `ALAND` - Land area (square meters)
- `AWATER` - Water area (square meters)
## Conversion to Other Formats
### GeoJSON (for web mapping)
```python
import geopandas as gpd
# Load shapefile
states = gpd.read_file("data/cache/census/shapefiles/2023/cb_2023_us_state_500k.zip")
# Convert to Web Mercator for web maps
states_web = states.to_crs("EPSG:3857")
# Save as GeoJSON
states_web.to_file("data/gold/boundaries/states.geojson", driver="GeoJSON")
```
### GeoParquet (for efficient storage)
```python
import geopandas as gpd
# Load shapefile
counties = gpd.read_file("data/cache/census/shapefiles/2023/cb_2023_us_county_500k.zip")
# Save as GeoParquet (smaller, faster than GeoJSON)
counties.to_parquet("data/gold/boundaries/counties.parquet")
# Load back
counties = gpd.read_parquet("data/gold/boundaries/counties.parquet")
```
### Simplified Geometries (for faster rendering)
```python
import geopandas as gpd
# Load and simplify
zcta = gpd.read_file("data/cache/census/shapefiles/2023/cb_2023_us_zcta520_500k.zip")
# Simplify to 100m tolerance (reduces file size)
zcta_simple = zcta.copy()
zcta_simple['geometry'] = zcta_simple.geometry.simplify(tolerance=100)
# Save simplified version
zcta_simple.to_file("data/gold/boundaries/zcta_simplified.geojson", driver="GeoJSON")
```
## Integration with Open Navigator
### 1. Jurisdiction Boundary Lookup
Match jurisdiction names to their geographic boundaries:
```python
import geopandas as gpd
import pandas as pd
# Load jurisdictions from Open Navigator
jurisdictions = pd.read_parquet("data/gold/jurisdictions_deduplicated.parquet")
# Load county boundaries
counties = gpd.read_file("data/cache/census/shapefiles/2023/cb_2023_us_county_500k.zip")
# Merge on name + state
merged = jurisdictions.merge(
counties[['GEOID', 'NAME', 'STATEFP', 'geometry']],
left_on=['jurisdiction_name', 'state_code'],
right_on=['NAME', 'STATEFP'],
how='left'
)
# Save with geometries
merged_gdf = gpd.GeoDataFrame(merged, geometry='geometry')
merged_gdf.to_parquet("data/gold/jurisdictions_with_boundaries.parquet")
```
### 2. Choropleth Mapping
Create interactive maps colored by data values:
```python
import geopandas as gpd
import folium
# Load state boundaries
states = gpd.read_file("data/cache/census/shapefiles/2023/cb_2023_us_state_500k.zip")
# Example: Count of jurisdictions per state
jurisdiction_counts = jurisdictions.groupby('state_code').size().reset_index(name='count')
# Merge with geometries
states_data = states.merge(
jurisdiction_counts,
left_on='STUSPS',
right_on='state_code',
how='left'
)
# Create choropleth map
m = folium.Map(location=[39.8, -98.5], zoom_start=4)
folium.Choropleth(
geo_data=states_data,
data=states_data,
columns=['STUSPS', 'count'],
key_on='feature.properties.STUSPS',
fill_color='YlOrRd',
legend_name='Jurisdiction Count'
).add_to(m)
m.save('jurisdiction_heatmap.html')
```
### 3. Spatial Joins
Find which jurisdictions overlap with which ZIP codes:
```python
import geopandas as gpd
# Load data
counties = gpd.read_file("data/cache/census/shapefiles/2023/cb_2023_us_county_500k.zip")
zcta = gpd.read_file("data/cache/census/shapefiles/2023/cb_2023_us_zcta520_500k.zip")
# Spatial join (find which county each ZCTA is in)
zcta_counties = gpd.sjoin(
zcta[['ZCTA5CE20', 'geometry']],
counties[['GEOID', 'NAME', 'geometry']],
how='left',
predicate='intersects'
)
# Save mapping
zcta_counties.to_parquet("data/gold/zcta_to_county_mapping.parquet")
```
## Use Cases in Open Navigator
### 1. Policy Heatmap Enhancement
- Add actual geographic boundaries to policy heatmap
- Show exact county/state shapes instead of markers
- Enable click-to-zoom on boundary
### 2. Geographic Search
- "Find all nonprofits in ZIP code 35401"
- "Show meetings within 50 miles of this location"
- Point-in-polygon lookups for jurisdiction detection
### 3. Service Area Visualization
- Display coverage areas for advocacy organizations
- Show legislative district boundaries
- Map nonprofit service regions
### 4. Data Validation
- Verify jurisdiction names against official boundaries
- Detect geocoding errors (city in wrong state)
- Fill missing location data using boundaries
## File Size Considerations
**Full Downloads:**
- States: ~3 MB
- Counties: ~15 MB
- ZCTAs: ~350 MB
- **Total: ~368 MB**
**Recommendations:**
- Store in `data/cache/` (excluded from git)
- Convert to GeoParquet for 50-70% size reduction
- Simplify geometries for web display
- Consider only downloading needed regions (e.g., priority states)
## License & Attribution
**License:** Public Domain (U.S. Government Work)
**Attribution (recommended):**
```
Boundary data from U.S. Census Bureau TIGER/Line Shapefiles
https://www.census.gov/geographies/mapping-files/time-series/geo/tiger-line-file.html
```
## Troubleshooting
### Installation Issues
If GeoPandas install fails:
```bash
# Use conda (easier for spatial packages)
conda install geopandas
# Or use pyogrio instead of fiona
pip install geopandas pyogrio
```
### CRS/Projection Issues
TIGER files use NAD83 (EPSG:4269). For web maps, convert to Web Mercator (EPSG:3857):
```python
gdf_web = gdf.to_crs("EPSG:3857")
```
### Large File Handling
For ZCTAs (350 MB), consider:
```python
# Load only needed columns
zcta = gpd.read_file("cb_2023_us_zcta520_500k.zip", columns=['ZCTA5CE20', 'geometry'])
# Filter to specific states
zcta_al = zcta[zcta['ZCTA5CE20'].str.startswith('35')] # Alabama ZCTAs
```
## Related Data Sources
- [Census ACS Data](./census-acs.md) - Demographic data for these boundaries
- [Jurisdiction Discovery](./jurisdiction-discovery.md) - Finding local governments
- [NCES Data](./census-data.md) - School district boundaries (separate)
## Next Steps
After downloading shapefiles:
1. Convert to GeoParquet for efficient storage
2. Join with Open Navigator jurisdiction data
3. Integrate into PolicyMap component for boundary display
4. Add spatial search capabilities to API