Build drive-time areas around sites with a routing service
Source:R/isochrone-dispatch.R
cacs_isochrone.RdBuilds 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
sfobject of points in EPSG:4326, or a data frame with numeric columnslonandlat(longitude and latitude). Ansfobject in another coordinate reference system, including NAD83 (EPSG:4269), gives an error. Either form needs a columnsite_idwith a different value for each site; a numericsite_idbecomes a string in the result. Without asite_idcolumn, a columnpoint_idis used assite_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 classcatchmentACS_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 infailure_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 defaultres; see the OSRM sections below.- ors_api_key
A string giving the openrouteservice API key, by default the value of the
ORS_API_KEYenvironment variable. It is used only withprovider = "ors"; see the "Provider status" section.- mapbox_token
A string, by default the value of the
MAPBOX_TOKENenvironment variable. It is not used (seeprovider), but a value that is not a single string, such asNULL, gives an error.- r5r_core
An r5r core object, or
NULL(the default). It is not used (seeprovider), 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
Dateobject or a string in the form year-month-day, such as"2025-04-01", orNULL(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 usecacs_cache_dir(). A folder outside the temporary folder of the R session is tidied as described incacs_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 ofcacs_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 defaultres, even whenverboseisFALSE.- ...
Additional named arguments, which depend on
provider. With OSRM, the accepted names areres, 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 byosrm_mode; andosrm.profileorosrm.profile_name, a profile name to use in the requests instead ofprofile. With openrouteservice, the accepted names areattributes,area_units, andsmoothing, which are passed on toopenrouteservice::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 typePOLYGONorMULTIPOLYGON, 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 inosm_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: alwaysNA.provider_requested: the service asked for, always the same asprovider.provider_downgrade: whether another service was used instead, alwaysFALSE.generated_at: the time the areas were built; a result read from the cache keeps the time of the original call.isochrone_empty:TRUEwhen 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"whenosm_snapshot_datewas given, otherwise"unknown_best_effort".failure_reason:NAwhen 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)
} # }