Census Loader
A Python wrapper around the U.S. Census Bureau API that abstracts away
variable codes, dataset endpoints, and FIPS identifiers behind a clean,
human-readable interface. Installs as census-loader, for anyone who pulls
Census data into pandas.
Instead of this:
data = census.acs5.get(
("B19013_001E",),
{"for": "county:*", "in": "state:25"},
year=2022
)
You write this:
cfg = Config(
"output.pkl", "./data",
year=2022,
geo="county_in_state",
state="Massachusetts",
series=["MEDIAN_HH_INCOME", "TOTAL_POP", "MEDIAN_RENT"],
)
result = pull_census(cfg)
Setup
pip install census-loader
Or from a checkout of this repository: pip install -e ..
Dependencies (installed automatically by pip; requirements.txt is kept
for reference): pandas, numpy, census, python-dotenv, requests.
Get a free key at
api.census.gov/data/key_signup.html,
then add it to a .env file in your project root:
CENSUS_API_KEY=your_key_here
Quickstart
from census_loader import Config, pull_census
cfg = Config(
"ma_counties.pkl", "./output",
year=2022,
geo="county_in_state",
state="Massachusetts",
series=["TOTAL_POP", "MEDIAN_HH_INCOME", "MEDIAN_RENT"],
)
result = pull_census(cfg) # dict of DataFrames keyed by friendly name
result["Median_Household_Income"]
Exploring the catalog
You never need to open series.py. Three discovery functions browse,
search, and inspect everything from a REPL or notebook:
available(): browse categories;available("INCOME")drills into a category or subcategory.search("poverty"): search by keyword.info("MEDIAN_HH_INCOME"): full details (name, category, dataset, underlying variable codes).geos(): browse geography templates.
Output format
pull_census returns a dict[str, pd.DataFrame] and saves a pickle to
your output path. Each DataFrame has geo columns on the left (FIPS codes +
human-readable names) and data columns on the right. Column naming depends
on the series type (single variable, multi-variable, group table); labels
are fetched automatically from the Census metadata API. pickle_loader
flattens a saved pickle to one DataFrame.
| Series type | Example key | Column names |
|---|---|---|
| Single variable | TOTAL_POP |
Total_Population |
| Multi-variable | HOMEOWNERSHIP_RATE |
Homeownership_Rate__Owner occupied, Homeownership_Rate__Total |
| Group table | HH_INCOME_BRACKETS |
Household_Income_Distribution__Less than $10,000, Household_Income_Distribution__$10,000 to $14,999, ... |
API limits
Free Census API keys allow 500 requests per day with a batch size of 50 variables per request. The loader sleeps 0.5s between calls to stay well under rate limits. Metadata label fetches are not rate-limited and are cached per session.
Reference
The sections below hold the full reference: Config options, series selection, geography templates, flattening into a single DataFrame, worked examples, and the complete category table.
Project layout
Census_Loader/
pyproject.toml
requirements.txt
README.md
.env-example
src/census_loader/
__init__.py # public API re-exports
utils.py # Config, loader, discovery tools
load.py # pull_census entry point
series.py # series catalog, GEO templates, FIPS codes
Config Reference
Config(
filename, # Output filename (auto-corrects to .pkl)
output_path, # Directory for output files
year=2022, # ACS/PEP vintage year
geo=..., # Geography level (see below)
state=..., # State name or FIPS code
county=..., # County FIPS (3-digit)
tract=..., # Tract code
series=..., # What to pull (see below)
batch_size=50, # Max series per API batch
)
Series selection
The series parameter accepts any granularity: individual series,
subcategories, categories, or a mix:
series=None # everything (169 series)
series="TOTAL_POP" # one series
series="INCOME" # whole category (18 series)
series="HOUSEHOLD_INCOME" # subcategory (9 series)
series=["TOTAL_POP", "INCOME", "MEDIAN_RENT"] # mix & match
series=["POVERTY", "HOUSEHOLD_INCOME", "TOTAL_POP"] # category + subcategory + series
Case-insensitive. Overlapping selections deduplicate automatically.
Geography
Pass a template name and fill in the required parameters:
# All states (default)
Config(..., geo="state_all")
# All counties in one state
Config(..., geo="county_in_state", state="Massachusetts")
# Tracts in one county
Config(..., geo="tract_in_county", state="Massachusetts", county="017")
# School districts in a state
Config(..., geo="school_district_in_state", state="Massachusetts")
# All ZCTAs
Config(..., geo="zcta_all")
State names resolve automatically, so "Massachusetts" and "25" both work.
For edge cases not covered by templates, pass a raw dict:
Config(..., geo={"for": "county:017", "in": "state:25"}).
Flattening into a single DataFrame
Since every series in a pull shares the same geography, you can merge on the shared geo columns:
from functools import reduce
import pandas as pd
frames = list(data.values())
shared = set(frames[0].columns)
for df in frames[1:]:
shared &= set(df.columns)
merge_keys = [c for c in shared
if all(not pd.api.types.is_numeric_dtype(df[c]) for df in frames)]
flat = reduce(
lambda left, right: pd.merge(left, right, on=merge_keys, how="outer"),
frames,
)
Examples
# County-level dashboard data for one state
cfg = Config(
"ma_dashboard.pkl", "./output",
year=2022, geo="county_in_state", state="Massachusetts",
series=["TOTAL_POP", "MEDIAN_HH_INCOME", "MEDIAN_RENT", "MEDIAN_HOME_VALUE",
"HOMEOWNERSHIP_RATE", "HH_INCOME_BRACKETS"],
)
pull_census(cfg)
# Tract-level deep dive
cfg = Config(
"middlesex_tracts.pkl", "./output",
year=2022, geo="tract_in_county", state="Massachusetts", county="017",
series=["TOTAL_POP", "MEDIAN_HH_INCOME", "POP_65_PLUS"],
)
pull_census(cfg)
# Full category pull, all states
cfg = Config("national_income.pkl", "./output", year=2022, series="INCOME")
pull_census(cfg)
# School district comparison
cfg = Config(
"ma_schools.pkl", "./output",
year=2022, geo="school_district_in_state", state="Massachusetts",
series=["TOTAL_POP", "MEDIAN_HH_INCOME", "HH_INCOME_BRACKETS"],
)
pull_census(cfg)
Available Categories
| Category | Series | Subcategories |
|---|---|---|
| POPULATION | 13 | TOTAL_POPULATION, AGE_DETAIL |
| RACE_ETHNICITY | 13 | RACE, HISPANIC_ORIGIN |
| NATIVITY_MIGRATION | 11 | NATIVITY, MIGRATION |
| LANGUAGE | 6 | none |
| EDUCATION | 10 | SCHOOL_ENROLLMENT, EDUCATIONAL_ATTAINMENT |
| HOUSEHOLDS | 12 | HOUSEHOLD_TYPE, MARITAL_STATUS, FERTILITY |
| INCOME | 18 | HOUSEHOLD_INCOME, EARNINGS, PUBLIC_ASSISTANCE |
| POVERTY | 12 | ACS_POVERTY, SAIPE_POVERTY |
| HEALTH_INSURANCE | 6 | ACS_HEALTH_INSURANCE, SAHIE_HEALTH_INSURANCE |
| EMPLOYMENT | 15 | EMPLOYMENT_STATUS, OCCUPATION_INDUSTRY, COMMUTING |
| HOUSING | 25 | HOUSING_UNITS, TENURE, HOME_VALUE, HOUSING_INFRASTRUCTURE |
| DISABILITY | 5 | none |
| VETERANS | 4 | none |
| PEP_POPULATION | 6 | none |
| DECENNIAL | 9 | DECENNIAL_REDISTRICTING, DECENNIAL_DHC |
| DATA_PROFILES | 4 | none |
| Total | 169 |
License
Start here
src/census_loader/series.py is the heart of this project: the catalog that
maps every friendly series name onto its Census variable codes, and the
reason the wrapper exists at all. src/census_loader/load.py then shows how
a Config becomes batched API calls and labelled DataFrames, and
tests/test_catalog.py shows the catalog's invariants.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file census_loader-0.1.0.tar.gz.
File metadata
- Download URL: census_loader-0.1.0.tar.gz
- Upload date:
- Size: 42.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0be28f8b130cf7ba08e1bbbe07deda73c38b74065a414b2e65bd0ecd3120e9b2
|
|
| MD5 |
263536f635d2cc0ba8eae623070906db
|
|
| BLAKE2b-256 |
de54b02bc91375590dbd3f3803d6e3d80704b8ea9e9b8c42f523ddce62125b72
|
Provenance
The following attestation bundles were made for census_loader-0.1.0.tar.gz:
Publisher:
tests.yml on iasolb/census-loader
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
census_loader-0.1.0.tar.gz -
Subject digest:
0be28f8b130cf7ba08e1bbbe07deda73c38b74065a414b2e65bd0ecd3120e9b2 - Sigstore transparency entry: 2821183276
- Sigstore integration time:
-
Permalink:
iasolb/census-loader@e34d9bca210c48fb3a54e4ea4fc990de8692ba52 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/iasolb
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
tests.yml@e34d9bca210c48fb3a54e4ea4fc990de8692ba52 -
Trigger Event:
push
-
Statement type:
File details
Details for the file census_loader-0.1.0-py3-none-any.whl.
File metadata
- Download URL: census_loader-0.1.0-py3-none-any.whl
- Upload date:
- Size: 28.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a8940482678af809c3dc28b9130002a28b03b0bdf55269805d3e79fd3c9a094d
|
|
| MD5 |
a3f8df2373ab767488b5c03f466d8573
|
|
| BLAKE2b-256 |
e9069881fa3e28c7f5e46555dfe50c84b9d27d4a0d306017c3e62510f8469513
|
Provenance
The following attestation bundles were made for census_loader-0.1.0-py3-none-any.whl:
Publisher:
tests.yml on iasolb/census-loader
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
census_loader-0.1.0-py3-none-any.whl -
Subject digest:
a8940482678af809c3dc28b9130002a28b03b0bdf55269805d3e79fd3c9a094d - Sigstore transparency entry: 2821183297
- Sigstore integration time:
-
Permalink:
iasolb/census-loader@e34d9bca210c48fb3a54e4ea4fc990de8692ba52 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/iasolb
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
tests.yml@e34d9bca210c48fb3a54e4ea4fc990de8692ba52 -
Trigger Event:
push
-
Statement type: