morpc-census provides tools to fetch Census geometries and data for specific places (scopes) at specific resolutions (scales). This notebook shows the typical workflow:
Choose a scope — where are we looking?
Choose a scale — at what resolution?
Fetch the geometries
Work with GEOIDFQs — the fully-qualified geographic IDs the Census API returns
from morpc_census import (
SCOPES,
SumLevel,
GeoIDFQ,
geoinfo_from_scope_sumlevel,
fetch_geos_from_scope_sumlevel,
)1. Scopes — choosing where¶
A scope names a geographic extent — a county, a multi-county region, the whole US. morpc-census ships with built-in scopes for the US, all 50 states, all Ohio counties, and several MORPC study areas.
# All available scope names
list(SCOPES.keys())# A single-county scope — Franklin County
SCOPES["franklin"]# A multi-county scope — the 15-county MORPC region
# for_param holds the FIPS codes of all counties in the region
SCOPES["region15"]2. Scales — choosing resolution¶
A scale (summary level) sets the resolution of the data — county, census tract, place, block group, etc. Pass a name or a three-digit Census code; both refer to the same thing.
# Look up a scale by name
SumLevel("county")# Same result from the three-digit code
SumLevel("050")# Unrecognised names raise a ValueError that lists all valid options
try:
SumLevel("neighborhood")
except ValueError as e:
print(e)3. Fetching geometries¶
Network required — the cells below call the Census API and TIGERweb REST API.
fetch_geos_from_scope_sumlevel(scope, sumlevel) is the primary entry point. When sumlevel is omitted it defaults to the scope’s own level (counties for region15, a single county for franklin).
# County boundaries for the 15-county MORPC region
region_counties = fetch_geos_from_scope_sumlevel("region15")
region_counties[["NAME", "GEOID", "geometry"]].head()region_counties.plot()# Census tract boundaries within Franklin County
franklin_tracts = fetch_geos_from_scope_sumlevel("franklin", "tract")
franklin_tracts[["NAME", "GEOID", "geometry"]].head()franklin_tracts.plot()Geographic IDs without geometry¶
geoinfo_from_scope_sumlevel queries the Census API for GEOIDFQs and names without downloading geometry — useful when you only need to enumerate geographies or collect IDs to pass to other queries.
# GEOIDFQs for all counties in the MORPC region (no geometry download)
geoinfo_from_scope_sumlevel("region15")# As a DataFrame with GEO_ID and NAME columns
geoinfo_from_scope_sumlevel("region15", output="table")# Drill down to a finer resolution
geoinfo_from_scope_sumlevel("franklin", "tract", output="table")4. GEOIDFQs¶
Every geography returned by the Census API has a GEOIDFQ — a fully-qualified geographic identifier that encodes the geography type and component FIPS codes in a single string.
For example, 1400000US39049010100 is the GEOIDFQ for census tract 101 in Franklin County, Ohio:
140 00 00 US 39 049 010100
─┬─ ─┬ ─┬ ─┬ ─┬─ ─┬─ ──┬──
│ │ │ │ │ │ tract
│ │ │ │ │ county
│ │ │ │ state
│ │ │ literal
│ │ geocomp
│ variant
sumlevel (140 = census tract)GeoIDFQ lets you parse, inspect, and construct these strings.
# Parse a GEOIDFQ string into its components
tract = GeoIDFQ.parse("1400000US39049010100")
tract# Summary level tells you what kind of geography this is
print(tract.sumlevel.name)
# Component FIPS codes
print(tract.parts)# .geoid is the short-form ID used in Census REST API queries
tract.geoid# Build a GEOIDFQ from a summary level code and component FIPS codes
county = GeoIDFQ.build("050", state="39", county="049")
str(county) # Franklin County, Ohio# GEOIDFQs from a fetch can be parsed directly from the GEOIDFQ column
geoidfqs = [GeoIDFQ.parse(fq) for fq in region_counties["GEOIDFQ"]]
[(g.parts["county"], g.geoid) for g in geoidfqs]