Skip to contents

Builds a drive-time area around each site for each drive time, using a routing service: the Open Source Routing Machine (OSRM, the default) or openrouteservice. Each area, also called an isochrone, covers the places that the routing service finds reachable from the site within that many minutes, so the 10-minute area includes the 5-minute area.

Usage

cacs_isochrone(
  sites,
  drive_times = c(5, 10, 15),
  provider = c("osrm", "ors", "mapbox", "r5r"),
  profile = "car",
  osrm_mode = c("demo", "docker"),
  ors_api_key = Sys.getenv("ORS_API_KEY"),
  mapbox_token = Sys.getenv("MAPBOX_TOKEN"),
  r5r_core = NULL,
  osm_snapshot_date = NULL,
  cache_dir = NULL,
  verbose = TRUE,
  ...
)

Arguments

sites

An sf object of points in EPSG:4326, or a data frame with numeric columns lon and lat (longitude and latitude). An sf object in another coordinate reference system, including NAD83 (EPSG:4269), gives an error. Either form needs a column site_id with a different value for each site; a numeric site_id becomes a string in the result. Without a site_id column, a column point_id is used as site_id, with a warning.

drive_times

A numeric vector of drive times in minutes: at most six values, each a whole number from 1 to 60; the default is c(5, 10, 15). The values can be in any order, and a repeated value is used once.

provider

A string giving the routing service: "osrm" (the default) for OSRM or "ors" for openrouteservice; see the "Provider status" section. "mapbox" and "r5r" are also accepted, but they are not implemented yet; using them gives an error of class catchmentACS_error_credential, after the other arguments are checked and before any request is sent.

profile

A string giving the routing profile, such as "car" (the default). With OSRM, the public demo server offers "car", "bike", and "foot"; with a profile that is not available, routing fails for every site and the error is recorded in failure_reason. With openrouteservice, the accepted values are the openrouteservice profiles "driving-car", "driving-hgv", "cycling-regular", "cycling-road", "cycling-mountain", "cycling-electric", "foot-walking", "foot-hiking", and "wheelchair", and the short names "car", "hgv", "bike" (for "cycling-regular"), "foot", and "walk" (both for "foot-walking"); any other value stops the function with the R error "subscript out of bounds".

osrm_mode

A string giving where OSRM requests are sent: "demo" (the default) for the public OSRM demo server or "docker" for a local OSRM server. It also sets the default res; see the OSRM sections below.

ors_api_key

A string giving the openrouteservice API key, by default the value of the ORS_API_KEY environment variable. It is used only with provider = "ors"; see the "Provider status" section.

mapbox_token

A string, by default the value of the MAPBOX_TOKEN environment variable. It is not used (see provider), but a value that is not a single string, such as NULL, gives an error.

r5r_core

An r5r core object, or NULL (the default). It is not used (see provider), but its class is checked.

osm_snapshot_date

A date to record as the date of the OpenStreetMap data used by the routing service: a Date object or a string in the form year-month-day, such as "2025-04-01", or NULL (the default). The date is only recorded in the result; it is not sent to the routing service and does not change the areas. A call with a different date does not reuse a saved result.

cache_dir

A path to the cache folder, or NULL (the default) to use cacs_cache_dir(). A folder outside the temporary folder of the R session is tidied as described in cacs_cache_dir().

verbose

A logical value. With TRUE (the default), the function shows a summary line when the step finishes and, with five or more sites, a line as each site finishes. See the "Progress messages" section of cacs_run() for how to turn them off or show the lines for any number of sites. The function shows the message that a saved result is returned, and the notices about the default res, even when verbose is FALSE.

...

Additional named arguments, which depend on provider. With OSRM, the accepted names are res, which sets how detailed the areas are (see the OSRM sections below); osrm.server, the address of an OSRM server to use instead of the one chosen by osrm_mode; and osrm.profile or osrm.profile_name, a profile name to use in the requests instead of profile. With openrouteservice, the accepted names are attributes, area_units, and smoothing, which are passed on to openrouteservice::ors_isochrones(). Other arguments give a warning and are not used.

Value

An sf tibble with one row for each site and drive time, in the order of sites and then by increasing drive time, and 16 columns:

  • site_id: the site identifier, converted to a string.

  • drive_time_min: the drive time in minutes.

  • geometry: the drive-time area, of geometry type POLYGON or MULTIPOLYGON, in longitude and latitude (EPSG:4326); empty when there is no area.

  • provider: the routing service used, "osrm" or "ors".

  • profile: the routing profile, such as "car".

  • osm_snapshot_date: the date given in osm_snapshot_date, as a string, or "unknown".

  • routing_engine_version: "osrm-pkg/" or "openrouteservice-pkg/" followed by the version of the R package that sent the requests (not the version of the routing server).

  • polygon_simplification_tolerance: always NA.

  • provider_requested: the service asked for, always the same as provider.

  • provider_downgrade: whether another service was used instead, always FALSE.

  • generated_at: the time the areas were built; a result read from the cache keeps the time of the original call.

  • isochrone_empty: TRUE when the row has no area, because routing failed or because the service returned no area for that drive time (with OSRM, for example, when the site is too far from the road network).

  • osm_snapshot_status: "user_supplied" when osm_snapshot_date was given, otherwise "unknown_best_effort".

  • failure_reason: NA when routing succeeded, otherwise the error message from the last attempt.

  • retry_count: the number of attempts made for the site, counting the first (1 to 3).

  • ring_topology: always "cumulative", meaning that each area includes the areas of the shorter drive times.

The attributes cacs_isochrone_provenance and cacs_provenance hold the same list, a record of how the result was produced: the cache key, provider, profile, osrm_mode, the snapshot date and status, ring_topology, and, for OSRM, the res value, the OSRM server and profile, and an estimate of the requests per site (osrm_request_budget). The attribute cacs_res_param holds the res value (NA for openrouteservice). Rows selected from the result keep these attributes, including the cache key that cacs_intersect_weight() uses to recognize the areas in its own cache.

Details

Routing for a site is tried up to three times, and not again after an HTTP 4xx error such as a bad request. A site for which routing fails keeps its rows, with an empty geometry and the error message in failure_reason; warnings report the number of rows that failed or have no area. If the routing service answers that its request limit has been reached (HTTP status 429), the function stops with an error as soon as that answer comes, sends no requests for the remaining sites, and returns no result. It does the same when the service refuses access (HTTP status 401 or 403), for example because an API key is not accepted.

The requests have no time limit of their own: a server that accepts the connection but does not answer makes the function wait, and a server that cannot be reached is tried three times for each site before the site is reported as failed. cacs_validate_osrm_endpoint() checks an OSRM server with a time limit and can be called first.

Unless the cache is turned off with cacs_set_cache(), the result is saved in the cache folder (cache_dir, or cacs_cache_dir()), which by default lasts only for the R session. A later call with the same arguments (other than verbose) and option settings returns the saved result without contacting the routing service, as long as the installed versions of sf, PROJ, and GEOS have not changed. A result is not saved when routing failed for a site because the service did not answer, timed out, or answered with an HTTP 5xx error, since a later call may succeed; a saved result with such a failure is deleted, and its sites are routed again. A site that the service refused with another HTTP 4xx error, such as a bad request, is saved with its failure_reason, and a warning is given each time the saved result is used. cacs_clear_cache() with namespace = "isochrone" removes only the results saved in the folder returned by cacs_cache_dir(), whose help page describes the cache folder, how long saved results are kept, and how they are checked.

Provider status

provider = "osrm" (the default) uses OSRM through the osrm package and needs no API key; osrm_mode chooses the server (see the OSRM sections below). provider = "ors" uses openrouteservice through the openrouteservice package and needs an API key, given in ors_api_key; if the key is empty, the function stops with an error of class catchmentACS_error_credential before any request is sent. The openrouteservice route has been checked only with simulated responses from openrouteservice, not with the service itself. The two services compute the areas in different ways, so the area for the same site and drive time can differ between them.

OSRM servers

With osrm_mode = "demo", the requests go to the public OSRM demo server at https://routing.openstreetmap.de/; with osrm_mode = "docker", they go to http://0.0.0.0:5000/, or to the address set in the option catchmentACS.osrm_docker_server. An address given in osrm.server (see ...) is used instead with either mode. With osrm_mode = "demo", the osrm package's own option osrm.server is also used. The osrm package sets that option to the demo server when it is loaded, for example by library(osrm), replacing a value set earlier; a value set before a call to this function is kept, even when the call loads osrm.

OSRM grid resolution

The osrm package draws the areas of a site from travel times to a grid of res by res points around it, sized for the longest drive time, so the areas for shorter drive times rest on fewer points. A larger res gives more detailed areas but needs more requests and more time. On the demo server, the osrm package waits one second after every 75 grid points that it sends, which comes to about 10 seconds for each site at res = 30L and about a minute at res = 70L. There is no such wait with other servers.

If res is not given, it is 70L with osrm_mode = "docker". The public demo server is protected by resolving res to 30L with osrm_mode = "demo". With the lower value, fewer requests are sent for each site, so the server is less likely to answer that its request limit has been reached (HTTP status 429). With options(catchmentACS.osrm_demo_budget_protect = FALSE), res is 70L with either mode. A message reports the value used, once per R session; its class is catchmentACS_message_demo_budget_protected for 30L and catchmentACS_message_res_default_changed for 70L. When res is given, such as res = 30L, res = 50L, or res = 70L, that value is used and neither message is shown.

From version 5.0.0, the osrm package may show the message "'res' is deprecated, use 'n' instead." for each site. The res value is still used, and n is not accepted by cacs_isochrone().

Areas built with another server, other OpenStreetMap data, or another res can differ, and so can the estimates computed from them.

See also

cacs_validate_osrm_endpoint() checks whether an OSRM server is accepting requests, and cacs_validate_iso() checks whether drive-time areas made with other tools are in the form that the package expects. The routing services, and how to use a local OSRM server, are described in vignette("providers", package = "catchmentACS") (https://joonho112.github.io/catchmentACS/articles/providers.html).

Other steps of the calculation: cacs_acs_prefetch(), cacs_derive_rates(), cacs_intersect_weight(), cacs_propagate_moe(), cacs_run()

Examples

# The 10-minute area that cacs_isochrone() built for one site in
# Birmingham, Alabama, with the public OSRM demo server, kept in a file that
# comes with the package
iso_bhm <- readRDS(system.file("extdata", "visual_walkthrough_fixture.rds",
                               package = "catchmentACS"))$iso_sf
sf::st_drop_geometry(iso_bhm)[, c("site_id", "drive_time_min", "provider",
                                  "isochrone_empty", "failure_reason")]
#> # A tibble: 1 × 5
#>   site_id   drive_time_min provider isochrone_empty failure_reason
#>   <chr>              <int> <chr>    <lgl>           <chr>         
#> 1 AL_BHM_01             10 osrm     FALSE           NA            

# A table with no rows: the area has the form that the package expects
cacs_validate_iso(iso_bhm)
#> # A tibble: 0 × 7
#> # ℹ 7 variables: severity <chr>, check <chr>, col <chr>, actual <chr>,
#> #   expected <chr>, fix_hint <chr>, example <chr>

# These calls send several dozen requests to the public OSRM demo server,
# which limits how many it accepts.
if (FALSE) { # \dontrun{
library(sf)
# The site at the center of the drive-time areas for AL_SITE_07 that come
# with the package (used in the examples of cacs_run() and others)
site_07 <- data.frame(site_id = "AL_SITE_07", lon = -85.365, lat = 31.655)

# 5-, 10-, and 15-minute areas from the public OSRM demo server
iso <- cacs_isochrone(site_07, drive_times = c(5, 10, 15))
st_drop_geometry(iso)[, c("site_id", "drive_time_min", "isochrone_empty")]

# A finer grid gives more detailed areas but takes longer
iso_fine <- cacs_isochrone(site_07, drive_times = c(5, 10, 15), res = 50L)
} # }