Builds drive-time areas around each site, one for each drive time, and
combines the American Community Survey (ACS) estimates of the census
tracts that overlap each area. These areas are also called isochrones.
Returns a table with an estimate and its margin of error (the half-width
of a confidence interval) for every site, drive time, and variable, plus
rows for five rates such as the poverty rate
(cacs_acs_default_rates). The function runs
cacs_acs_prefetch(), cacs_isochrone(), cacs_intersect_weight(),
cacs_propagate_moe(), and cacs_derive_rates() in that order; each of
them can also be called on its own. Supplying precomputed_isochrones or
acs skips the corresponding step, and with both supplied no routing
service or Census API key is needed.
Usage
cacs_run(
sites,
state,
year = 2023,
drive_times = c(5, 10, 15),
variables = NULL,
provider = c("osrm", "ors", "mapbox", "r5r"),
weight_method = c("area", "population"),
moe_formula = NULL,
output = c("long", "list_column", "both"),
precomputed_isochrones = NULL,
cache_dir = NULL,
acs = NULL,
bg_pop_sf = NULL,
rates = cacs_acs_default_rates,
formula_dispatch = "general_ratio_conservative",
iso_args = list(),
acs_args = list(),
weight_args = list(),
moe_args = list(),
rate_args = list(),
verbose = TRUE
)Arguments
- sites
A data frame with the columns
site_id,lon, andlat, or ansfobject of points with asite_idcolumn, such ascacs_alabama_sites. The coordinates are longitude and latitude on WGS 84 (ansfobject must be in EPSG:4326), and thesite_idvalues must be unique.- state
A string giving one state, the District of Columbia, or Puerto Rico, as a two-letter USPS abbreviation (such as
"AL") or a two-digit FIPS code (such as"01"). Lowercase codes, such as"al", give an error unless the ACS data are supplied throughacs. Only the tracts of this state are downloaded, so the part of a drive-time area in another state adds nothing to the estimates unlessacsalso holds the tracts of that state (see the Details ofcacs_intersect_weight(), which also say what happens toacs_year). Data for Alaska, Hawaii, or Puerto Rico give an error at the intersection step.- year
A single whole number giving the last year of the ACS 5-year estimates, from 2009 to 2024; the default is 2023 (the 2019-2023 estimates).
- drive_times
A numeric vector of drive times in minutes; the default is
c(5, 10, 15). When the areas are built, up to six whole numbers from 1 to 60 are accepted.- variables
A character vector of ACS variable codes, or
NULL(the default) forcacs_acs_default_vars; seecacs_acs_prefetch()for the accepted codes. Codes outsidecacs_acs_default_varsare combined as counts, except those of tablesB19013andB25077(medians) andB19301(per capita income), so a median or per-person value from any other table is added up over the tracts like a count, without a warning (seecacs_intersect_weight()). Rates whose codes incacs_acs_default_ratesare left out areNA, with a warning.- provider
A string giving the routing service used to build the drive-time areas.
"osrm"(the default) uses the Open Source Routing Machine (OSRM) through a public server that needs no key; it requires the osrm package."ors"uses openrouteservice, which requires the openrouteservice package and an API key in theORS_API_KEYenvironment variable or iniso_args = list(ors_api_key = ...)."mapbox"and"r5r"are accepted names, but building areas with them is not implemented yet. Using them gives an error at the routing step, so the ACS data are downloaded first unlessacsis supplied. Whenprecomputed_isochronesis supplied, no areas are built, andprovideris only recorded in thecacs_run_provenanceattribute and shown when the result is printed.- weight_method
A string giving the weighting method:
"area"(the default) or"population". With"area", counts are added up with each tract weighted by the share of its area inside the drive-time area, which assumes that whatever a variable counts is spread evenly over each tract's area. The rates are ratios of these counts. Medians and per-person values are averaged with weights proportional to each tract's area inside the drive-time area. These weights ignore how many people live in each tract, so the average can be far from the value for the drive-time area when the tracts differ in population density (seecacs_intersect_weight())."population"is not implemented yet and gives an error before any step runs.- moe_formula
A string, or a list of strings named by ACS variable code, passed to
cacs_propagate_moe()as itsformulaargument, orNULL(the default). Each ACS variable accepts only the formula for its kind ("weighted_sum"for a count,"weighted_mean"for a median or per-person value), and any other choice gives an error. The formulas for the rates are chosen byformula_dispatch.- output
A string choosing the form of the result, as described in the Value section:
"long"(the default),"list_column", or"both".- precomputed_isochrones
An
sfobject of drive-time areas as returned bycacs_isochrone()(seecacs_validate_iso()for data from other sources), orNULL(the default) to build them withprovider. When supplied, the routing step is skipped and every area in it is used.sitesanddrive_timesdo not select areas from it; they are recorded in thecacs_run_provenanceattribute and shown when the result is printed. A site insitesthat has no area in it gets no rows and no warning. Ifprecomputed_isochroneshas areas for sites that are not insites, the numbers of sites shown when the result is printed are wrong (seeprint.cacs_run_result()). Areas withisochrone_empty = TRUEor afailure_reasonare treated as routing failures (see Details).- cache_dir
A path to the cache folder, or
NULL(the default) to usecacs_cache_dir(). It is used for the ACS data, drive-time areas, and intersection results thatcacs_acs_prefetch(),cacs_isochrone(), andcacs_intersect_weight()save. A folder outside the temporary folder of the R session is tidied as described incacs_cache_dir().- acs
An
sfobject of ACS tract estimates as returned bycacs_acs_prefetch()(seecacs_acs_validate()for data from other sources), orNULL(the default) to download them with tidycensus; downloading needs a Census API key (seecacs_acs_prefetch()). When supplied, the download step is skipped, every variable in it is used (variablesis ignored), andstateandyearare only recorded in thecacs_run_provenanceattribute. Census Bureau annotation codes, such as-555555555, are treated as missing, so a rate that uses such a value isNAfor the areas that include the tract, and two rows for the same tract and variable give an error (seecacs_intersect_weight(), which also says when a warning is given). When a tract has a row for one code of a rate and not for the other, for example after rows with a missing estimate were removed, the rate is computed over different tracts without a warning (see the "Tract counts for rates" section ofcacs_derive_rates()). Variable codes thatcacs_intersect_weight()does not combine, such as"C17002_002"or"B19013A_001", makecacs_propagate_moe()stop with an error.- bg_pop_sf
An
sfobject of block-group population estimates, orNULL(the default). It has no effect on the result (seeweight_method).- rates
A named list giving the numerator and denominator ACS codes of each rate. Only
cacs_acs_default_rates(the default), the list of the five built-in rates, is accepted; any other list, including a subset or a reordering of it, gives an error.- formula_dispatch
A string choosing the margin-of-error formula for the five rates.
"general_ratio_conservative"(the default) uses the ratio formula for every rate."auto"and"proportion_subset"use the proportion formula forpoverty_rateandlabor_force_participationand keep the ratio formula forsnap_rate,ssi_rate, andunemp_rate;"proportion_subset"also gives a warning naming those three.- iso_args
A named list of arguments passed on to
cacs_isochrone()when the areas are built, or an empty list (the default). The accepted names areosrm_mode,ors_api_key,mapbox_token,r5r_core,profile,osm_snapshot_date, andres; other names give a warning and are dropped. Becauseosrm.serveris not accepted, another OSRM server is used by settingosrm_mode = "docker"and the optioncatchmentACS.osrm_docker_server(see the "OSRM servers" section ofcacs_isochrone()).- acs_args
A named list of arguments passed on to
cacs_acs_prefetch()whenacsisNULL, or an empty list (the default). The accepted names aresurvey,geography,force_refresh, andwrite_gpkg; other names give a warning and are dropped.- weight_args
A named list of arguments passed on to
cacs_intersect_weight(), or an empty list (the default). The accepted names aremin_weightandkeep_tract_audit; other names give a warning and are dropped.- moe_args
A named list of arguments passed on to
cacs_propagate_moe(), or an empty list (the default). The accepted names arelevel, which sets the confidence level of all the margins of error (0.9 by default), andfallback_chain_max, which has no effect and gives a warning (seecacs_propagate_moe()). The nameformulagives an error (moe_formulasets it), and other names give a warning and are dropped.- rate_args
A named list of arguments for
cacs_derive_rates(), or an empty list (the default). No names are accepted:formula_dispatchgives an error (the argumentformula_dispatchsets it), and any other name gives a warning and is dropped.- verbose
A logical value, passed to each step that
cacs_run()runs. IfTRUE(the default), messages report which steps run and how each step progresses; see the "Progress messages" section.
Value
With output = "long" (the default), a tibble that also has the
class cacs_run_result, with one row for each site, drive time, and
variable, where the variable is an ACS variable or one of the five
rates. With output = "list_column", a tibble of the same class with
one row for each site and drive time. With output = "both", a plain
list with the elements long and list_column, one of each form.
The long form has these columns:
site_id,drive_time_min,variableThe site, the drive time in minutes, and the ACS variable code or rate name.
ring_topologyAlways
"cumulative": each drive-time area contains the shorter ones.estimate,moeThe estimate and its margin of error, at the confidence level given by the
cacs_confidence_levelattribute. For an ACS variable, both areNAwhen a tract's estimate is missing, andmoeisNAwhen a tract's margin of error is missing.weight_sumThe sum of the coverage weights of the tracts combined (a tract's coverage weight is the share of its area inside the drive-time area); for a rate, the smaller of the sums for its numerator and denominator, and
NAon a rate row whosefailure_originis"carrier".n_tractsThe number of tracts combined;
NAon rate rows.n_tracts_num,n_tracts_denOn rate rows, the numbers of tracts combined for the numerator and for the denominator;
NAon other rows and on a rate row whosefailure_originis"carrier"(seecacs_derive_rates()).provider,profile,osm_snapshot_dateThe routing service, the routing profile (such as
"car"), and the date of the OpenStreetMap data, as recorded on the drive-time areas.acs_yearThe ACS year from the
cacs_provenanceattribute thatcacs_acs_prefetch()puts on the ACS data;NAwhen the data have no such attribute, as with the sample ACS data in the package.weight_method,weight_basisThe weighting method (
"area") and the weights used (see theweight_methodargument):"coverage"for counts and rates, and"area_mean"for medians and per-person values.estimand_familyThe kind of quantity:
"spatial_total"(a count),"median_proxy"(a median),"area_weighted_scalar_proxy"(a per-person value such as per capita income), or"derived_rate"(a rate).moe_formula_requested,moe_formula_effectiveThe margin-of-error formula chosen, through
moe_formulaorformula_dispatch(seecacs_derive_rates()for the rates), and the one used:"weighted_sum","weighted_mean","proportion_subset"(the proportion formula), or"general_ratio_conservative"(the ratio formula). A rate row whosefailure_originis"carrier"has no margin of error, and both columns then name the formula that was chosen for it rather than one that was used.moe_fallback,moe_fallback_reasonFor a rate, whether the chosen formula could not be used, and why:
"negative_variance"(the ratio formula was used instead) or"zero_denominator"(the rate and its margin of error areNA);"n/a"otherwise.failure_originThe step at which the row failed:
"none";"isochrone"(the routing service returned no area; the row's estimates and most other values areNA);"intersection"(no tract is left for the area; the pair has one such row, withvariable = NAandn_tracts = 0); or"carrier"(the rate isNAbecause its numerator or denominator, or the margin of error of either, is missing, as for the rates of a pair with no tract).weight_uncertainty_propagatedFALSE: the margins of error treat the weights as fixed.
The columns est_total, var_total_raw, est_mean, and
var_mean_raw hold the weighted sums and averages of the tract
estimates, with their variances, from which estimate and moe are
computed (see cacs_propagate_moe()). They are NA on rate rows. With
options(cacs.return_se = TRUE), a column se (the standard error)
follows; it is also NA on rate rows.
The list-column form has these columns:
site_idThe site.
lon,latThe values of the columns of the same names in
sites, orNAwhensiteshas no such columns, even if it is ansfobject such ascacs_alabama_sites; the point coordinates are not used.drive_time_minThe drive time in minutes.
isochroneThe drive-time area, as a one-row
sfobject.acs_estimates,derived_ratesTibbles of the rows of the long result for that site and drive time: the ACS variables and the rates.
metadataA list of
provider,profile,osm_snapshot_date,acs_year,weight_method,failure_origin, andn_tracts, taken from the first row ofacs_estimates.
Both forms have these attributes:
cacs_schema_versionThe version label (
"1.0") of the column layout.cacs_run_provenanceA list recording how the result was produced. It gives the settings of the call:
state,year,drive_times,provider,weight_method,moe_formula,formula_dispatch,output_format,level(the confidence level), andmin_weight. It records which steps were skipped because their input was supplied, inbypass_iso,bypass_acs, andexecution_path. It also holds counts of sites and of pairs that succeeded or failed, the time of the run, and the package and R versions.cacs_run_warningsA list of the warnings given by each step, in the elements
acs_prefetch,isochrone,intersect_weight,propagate_moe, andderive_rates; when pairs failed at the routing step, the elementorchestratorhas an entry whosefailed_pairslists them, with the reason.cacs_aggregation_provenance,cacs_moe_provenance,cacs_rate_provenanceThe settings and counts recorded by
cacs_intersect_weight(),cacs_propagate_moe(), andcacs_derive_rates(); the last includes the formula chosen for each rate.cacs_confidence_levelThe confidence level of the margins of error (0.9 unless
moe_argssets anotherlevel).cacs_run_result_metadataA list that
print()andsummary()use: the time the result was created, the package version, the routing service and profile, and the drive times. It also holds counts of sites, the running time (wall_clock_seconds),skipped_geoids, and counts of rate rows bymoe_fallback_reason(moe_fallback_summary).
The long form also keeps skipped_geoids, the tracts skipped because
they have no area (see cacs_intersect_weight()), and
cacs_rate_audit, the result of the check of each rate against a fixed
range that options(catchmentACS.audit_rates = TRUE) turns on (see
cacs_derive_rates()). With
weight_args = list(keep_tract_audit = TRUE), it also keeps
cacs_tract_audit, a table of the tracts in each area with their
coverage weights. cacs_describe() prints a summary drawn from these
attributes.
Details
Margins of error are at the 90 percent level unless moe_args sets
another level, and they treat the tract estimates as independent (see
cacs_propagate_moe()). By default, every rate uses the formula that the
Census Bureau's handbook gives for a ratio of two estimates. The five
rates are proportions, for which the handbook gives a separate formula
whose margins are never wider; formula_dispatch can select it for
poverty_rate and labor_force_participation.
Site and drive-time pairs for which the routing service returns no area
stay in the result with NA values and failure_origin = "isochrone"
(failure_origin records the step at which a row failed), and a warning
reports how many pairs failed. A routing failure stops the function in two
cases: no pair succeeds, or the routing service refuses a request because
its request limit has been reached or an API key is not accepted.
Progress messages
The five steps report their progress with messages, whether they are run
by cacs_run() or called on their own. Each step counts its work in
units: sites for cacs_isochrone(), site and drive-time pairs for
cacs_intersect_weight(), and a single unit for the other three steps. A
step can show a summary line when it finishes, with how many units
succeeded out of how many, the time taken, and any failures. It can also
show a progress line as each unit finishes. An example is
Intersect+weight: 21/60 (ETA 0:01) - AL_SITE_07/15min, where ETA
is the estimated time left. cacs_propagate_moe() and
cacs_derive_rates() show at most the summary line.
The first of these rules that applies decides what a step shows:
With
verbose = FALSE, no progress messages.If the environment variable
CACS_QUIETis"1"(other values are ignored), no progress messages.If
getOption("catchmentACS.progress")is"off", no progress messages; if it is"force", the summary line and the progress lines, whatever the number of units.Otherwise, as with
"auto"or when the option is not set (the default), the summary line alone for fewer than five units, and the summary line and the progress lines for five or more.
With more than 50 units, only the first progress line, every tenth line
after it, and the last line are shown;
options(catchmentACS.progress_throttle = k) changes ten to k. A step
whose result is read from the cache shows no progress messages. These
settings do not affect warnings.
With verbose = TRUE, cacs_run() also shows messages of its own. A
message at the start says which steps will run, and one message is shown
for each step skipped because acs or precomputed_isochrones was
supplied. At the end, a message gives the numbers of site and drive-time
pairs that succeeded and failed. In the same way,
cacs_intersect_weight() shows a message before it starts, and
cacs_acs_prefetch() one before it downloads. Rules 2 and 3 leave these
messages on; verbose = FALSE turns them off. With
output = "list_column" or "both", a message about the isochrone
column is shown on every call, whatever verbose is.
All of these are ordinary R messages, so suppressMessages() also hides
them. Progress lines have the condition class
catchmentACS_message_progress_tick and summary lines the class
catchmentACS_message_progress_summary. Both also have the class
catchmentACS_message_progress, as do the messages of cacs_run() and
cacs_intersect_weight() that verbose = FALSE turns off, so
cacs_capture_conditions() with that class in classes collects all of
them. The condition classes of the package are listed in
catchmentACS-conditions.
References
U.S. Census Bureau (2020). Understanding and Using American Community Survey Data: What All Data Users Need to Know. Chapter 8, Calculating Measures of Error for Derived Estimates.
See also
The help pages print.cacs_run_result(),
summary.cacs_run_result(), and as_tibble.cacs_run_result() describe
how the result is printed, summarized, and converted to a plain tibble.
vignette("getting-started", package = "catchmentACS")
(https://joonho112.github.io/catchmentACS/articles/getting-started.html)
walks through a first run, and
vignette("methodology", package = "catchmentACS")
(https://joonho112.github.io/catchmentACS/articles/methodology.html)
describes the calculations.
Other steps of the calculation:
cacs_acs_prefetch(),
cacs_derive_rates(),
cacs_intersect_weight(),
cacs_isochrone(),
cacs_propagate_moe()
Examples
# Turn the cache off while this example runs (see ?cacs_set_cache).
old <- options(catchmentACS.cache_enabled = FALSE)
# Example data bundled with the package: the drive-time areas are circles
# with a radius of 1 km per minute, and the ACS data are made up. The
# routing columns of the areas, such as provider, hold fixed values that
# do not come from a routing service, and the result repeats some of them.
library(sf)
iso <- readRDS(system.file("extdata", "legacy_2025_isochrones.rds",
package = "catchmentACS"))
acs <- readRDS(system.file("extdata", "sample_alabama_subset.rds",
package = "catchmentACS"))
iso_07 <- iso[iso$site_id == "AL_SITE_07" & iso$drive_time_min == 10, ]
# The site at the center of these areas
site_07 <- data.frame(site_id = "AL_SITE_07", lon = -85.365, lat = 31.655)
# With both the drive-time areas and the ACS data supplied, no routing
# service, Census API key, or internet connection is needed.
out <- cacs_run(site_07, state = "AL", drive_times = 10,
precomputed_isochrones = iso_07, acs = acs,
verbose = FALSE)
# The five rates for the 10-minute area of AL_SITE_07
tibble::as_tibble(out) |>
dplyr::filter(variable %in% names(cacs_acs_default_rates)) |>
dplyr::select(variable, estimate, moe)
#> # A tibble: 5 × 3
#> variable estimate moe
#> <chr> <dbl> <dbl>
#> 1 poverty_rate 0.602 0.0984
#> 2 snap_rate 0.0426 0.00557
#> 3 ssi_rate 0.165 0.0360
#> 4 unemp_rate 0.0630 0.0149
#> 5 labor_force_participation 0.846 0.112
options(old)
# Needs a Census API key, and builds the areas of five sites on the public
# OSRM demo server, which limits the requests it accepts.
if (FALSE) { # \dontrun{
library(sf)
out_live <- cacs_run(cacs_alabama_sites[1:5, ], state = "AL", year = 2023,
drive_times = c(5, 10, 15), provider = "osrm")
# The poverty rate for each site and drive time, highest first
tibble::as_tibble(out_live) |>
dplyr::filter(variable == "poverty_rate") |>
dplyr::arrange(dplyr::desc(estimate)) |>
dplyr::select(site_id, drive_time_min, estimate, moe)
} # }