catchmentACS describes the neighborhoods around a set of sites, such as pre-kindergarten (Pre-K) classrooms, with data from the American Community Survey (ACS). For each site and each drive time, such as 5, 10, and 15 minutes, it finds the area that can be reached by car within that time, the site's catchment. It then combines the ACS estimates of the census tracts that overlap the catchment into estimates for it: how many people live there, how many are below the poverty level, what share of households receive benefits from the Supplemental Nutrition Assistance Program (SNAP), and so on. Every estimate comes with a margin of error, the half-width of its 90 percent confidence interval, and with a record of the settings and inputs behind it.
For a count, each tract contributes the share of its own area that lies inside the drive-time area: a tract half inside contributes half of its count. This assumes that whatever a variable counts is spread evenly over a tract: the people below the poverty level, and not only the population as a whole. Each rate is the ratio of two counts computed this way. Medians and per-person values from three ACS tables (median household income, median home value, and per capita income) are averaged over the overlapping tracts instead, with weights proportional to the area each tract shares with the area. Those weights ignore how many people live in each tract, so such an average can be far from the median of the area itself. A median or per-person value from any other ACS table is added up like a count. The articles listed below describe the calculations and what they assume.
When catchmentACS is available on CRAN, install.packages("catchmentACS")
installs the released version. The development version is on GitHub:
# install.packages("pak")
# pak::pak("joonho112/catchmentACS")
install.packages("catchmentACS", repos = c('https://joonho112.r-universe.dev', 'https://cloud.r-project.org'))
pak::pak() does not build the articles; they are on the package website,
https://joonho112.github.io/catchmentACS/articles/. Building drive-time areas
with the default routing service needs the osrm package, and the package's maps
need the leaflet package. Neither is installed with catchmentACS:
install.packages(c("osrm", "leaflet"))
Downloading ACS data needs a free Census API key, which can be requested at https://api.census.gov/data/key_signup.html and saved with:
tidycensus::census_api_key("YOUR_KEY_HERE", install = TRUE)
readRenviron("~/.Renviron")
The first line saves the key in ~/.Renviron for later sessions; the second
makes it usable in the session that is running. A key already saved there needs
overwrite = TRUE.
The key is needed only when catchmentACS downloads estimates: when no saved result
of them matches the call, or when force_refresh = TRUE. A run that supplies estimates through
acs =, like the example below, needs no key.
This product uses the Census Bureau Data API but is not endorsed or certified by the Census Bureau.
Downloaded estimates and drive-time areas are saved for the rest of the R
session, so a repeated call neither downloads nor routes again. To keep them
between sessions, add this line to the R startup file, for example with
usethis::edit_r_profile():
options(catchmentACS.cache_dir = tools::R_user_dir("catchmentACS", "cache"))
Saved results in that folder that go unused for 30 days are deleted.
?cacs_cache_dir gives the details.
Everything the example needs comes from three files that ship with the package.
They hold made-up data: 20 sites on a grid over a rectangle around Alabama,
drive-time areas drawn as circles around the sites, and random ACS estimates
for 911 small squares that stand in for census tracts. Given the areas and the
estimates, cacs_run() skips the steps that build the areas and download the
estimates, so the example contacts no service and needs no key.
library(catchmentACS)
library(dplyr)
library(sf) # needed to subset the bundled sf objects with [
sites <- readRDS(system.file(
"extdata", "legacy_2025_sites.rds", package = "catchmentACS"
))
iso <- readRDS(system.file(
"extdata", "legacy_2025_isochrones.rds", package = "catchmentACS"
))
acs <- readRDS(system.file(
"extdata", "sample_alabama_subset.rds", package = "catchmentACS"
))
one_site <- "AL_SITE_07"
result <- cacs_run(
sites = sites[sites$site_id == one_site, , drop = FALSE],
state = "AL",
precomputed_isochrones = iso[iso$site_id == one_site, , drop = FALSE],
acs = acs,
verbose = FALSE
)
tibble::as_tibble(result) |>
filter(variable %in% names(cacs_acs_default_rates)) |>
select(site_id, drive_time_min, variable, estimate, moe)
The call returns one row for each drive time and rate, with an estimate and its
margin of error, and the same for each ACS variable in acs. Down the column
for this site the poverty rate is 0.62 for the 5-minute area and 0.36 for the
15-minute area, and the share of households receiving SNAP benefits is 0.04 and
0.11. These numbers describe no real place. The bundled ACS values are random,
and the made-up squares are spaced apart rather than tiling the state, so the
5-minute area overlaps one square and the two wider areas overlap three: the
change down the column is the change from one square's values to an average of
three. The file ships with the package, so every reader gets the same numbers.
For some other sites a rate has no value, because one made-up estimate in
twenty is missing; the run then warns and leaves NA in estimate and moe.
AL_SITE_07 has no such row.
For a run on your own sites, the call is the same without
precomputed_isochrones = and acs =. The sites go in as a data frame with
the columns site_id, lon, and lat, or as an sf object of points with a
site_id column. The run then needs a routing service, a Census API key, and
an internet connection.
Getting started with catchmentACS
goes through the result column by column, and
Routing services, API keys, and offline use
covers the routing services and their keys.
ORS_API_KEY environment
variable, ors_api_key = in cacs_isochrone(), or
iso_args = list(ors_api_key = ...) in cacs_run(). The openrouteservice
route has been checked only with simulated responses from openrouteservice.Not implemented yet: Mapbox and r5r as routing services, weighting by
population, rates other than the five above, and ACS pulls of 1-year estimates,
block groups, counties, or several states at once. Asking for any of these
stops the run with an error naming what is missing. Weighting by population, a
different rates list, and several states in state = give the error no
matter what else is supplied. The other five give it only when the step that
would use them runs. With precomputed_isochrones = supplied the routing step
does not run, so provider = "mapbox" is accepted and left unused; with
acs = supplied the download step does not run, so
acs_args = list(survey = "acs1") is too.
The articles below are on the package website. vignette("name", package = "catchmentACS") opens one locally when the installed package includes the
articles. A version installed from CRAN includes them. A version installed from
GitHub includes them only when they are built during installation, as with
remotes::install_github("joonho112/catchmentACS", build_vignettes = TRUE), or
with devtools::install(build_vignettes = TRUE) from a local copy.
| Article | What it covers |
|---|---|
| Getting started with catchmentACS | A first run on the example data, and how to read the result. |
| A worked example with Alabama Pre-K sites | The five steps one at a time, then tables for a report. |
| Routing services, API keys, and offline use | Which services are implemented, what keys they need, and how to run without a network. |
| Mapping each step for one Birmingham site | Leaflet maps of the drive-time areas, the tracts, the weighted estimates, and the rates. |
| Article | What it covers |
|---|---|
| How the estimates are computed | The calculation from tracts to catchment estimates, and its assumptions. |
| Area weighting of tract estimates | The two weights, and when an area-weighted average stands in for a median. |
| Margins of error for combined estimates | How the margins of error of the tracts combine, and what the formulas leave out. |
| Rates and their margins of error | The five rate definitions and the two formulas for the margin of error of a rate. |
| Article | What it covers |
|---|---|
| Updating code written for versions 0.1 and 0.2 | The ten changes that reach code written for 0.1 or 0.2. |
| Updating code written for version 0.3 | What changed in 0.4. |
| Updating code written for version 0.4 | What changed in 0.5.0, including the corrected medians and per-person values. |
Help pages for the functions are on the website as well. ?cacs_run describes
every argument of the one call that runs the whole calculation.
catchmentACS is written by JoonHo Lee
(ORCID: 0009-0006-4019-8703).
citation("catchmentACS") gives the citation for the installed version, and
toBibtex(citation("catchmentACS")) gives it as a BibTeX entry.
MIT © JoonHo Lee
Bug reports and feature requests are welcome at https://github.com/joonho112/catchmentACS/issues.