The package wraps the US Census Bureau API into a pandas-based data pipeline. Data always flows wide → long → DimensionTable → wide/percent.
api.py— Core pipeline:Endpoint(survey + year),Group(variable group),CensusAPI(fetches + melts to long),DimensionTable/RaceDimensionTable(pivots + percentages). All network calls are lazy-cached via@functools.cacheor@cached_property.geos.py— Geography layer:Scope(named query extent),SumLevel(summary level code ↔ query name),GeoIDFQ(GEOID parser). TheSCOPESdict is the primary registry of named geographic extents (e.g.region15,franklin).SCOPESis a_LazyScopesinstance that defersimport morpcuntil first access, keeping import side-effect free.tigerweb.py— Fetches GeoDataFrames from the TIGERweb REST API. Thecurrent_endpointsdict maps human-readable layer names to integer layer IDs — hand-maintained and can drift from the live API.constants.py— Pure data: lookup tables and sort orders for age groups, race, education, income-to-poverty, etc. No I/O.
Census API (wide CSV)
└─ CensusAPI.data # raw wide DataFrame, one col per variable
└─ CensusAPI.long # melted: geoidfq × variable, with estimate/moe columns
└─ DimensionTable
├─ .wide() # MultiIndex DataFrame: dim rows × (survey, geoidfq, …) cols
├─ .percent() # same shape; estimate=% of total, MOE via Census proportion formula
├─ .remap() # collapse variable labels, aggregate estimates + MOE
└─ .drop() # remove a dimension level ('summarize' or 'aggregate')
CensusAPI.save(path) writes three files: {name}.long.csv, {name}.schema.yaml, {name}.resource.yaml (frictionless descriptors).
CensusAPI.load(resource_path) is the inverse: it reads those files back into a CensusAPI instance without re-fetching survey data. The resource descriptor embeds a _morpc block (constructor args: survey, year, scope, sumlevel, group, variables) so the instance can be rebuilt faithfully; long is read from the CSV, request is restored from the descriptor's sources, and data is reconstructed from long via _long_to_data() (the inverse of melt()). Resources saved before _morpc existed cannot be loaded.
- No network on import.
Endpoint.vintages,Endpoint.groups,Group.variablesare all@cached_property;get_all_avail_endpoints()and_get_api_key()are@functools.cache. - Variable batching. The Census API allows ~50 fields per request;
_fetch_variablesbatches at 48 and joins onGEO_ID. When agroupis set,_fetch_groupuses thegroup(CODE)endpoint instead (no 50-field limit). - MOE propagation. Aggregation:
sqrt(sum(moe²)). Percentage: Census Bureau derived proportion formula with fallback to addition form when radicand is negative. - Long-format model. Variable labels use
!!-delimited hierarchy (e.g.Total:!!Male:!!Under 5 years).DimensionTable._parse_dims()splits these into subtotal columns (ending with:) and leaf columns, then stores each as an ordered categorical. morpcdependency.morpc>=0.5.4is a declared dependency that resolves from PyPI. It providesSUMLEVEL_DESCRIPTIONS,morpc.req.get_json_safely, andmorpc.req.get_text_safely.
| Suffix | Meaning |
|---|---|
E |
Estimate |
M |
Margin of error |
PE |
Percent estimate |
PM |
Percent MOE |
N |
Total |
Census missing-value sentinels (-222222222, -999999999, etc.) are coerced to NaN during melt().