| Title: | Client for OGC API - Environmental Data Retrieval (EDR) |
| Version: | 0.1.1 |
| Description: | A tidy R client for services implementing the OGC API - Environmental Data Retrieval ('EDR') standard with JSON discovery and 'GeoJSON' or 'CoverageJSON' query responses. General purpose, but most of its real-world use is against in-situ monitoring networks (stream gauges, weather stations, snow and reservoir telemetry) that expose their stations and time series as EDR collections. Known working endpoints include the USGS waterdata OGC API and the Western Water Datahub. Provides discovery, query, and parsing helpers for the locations, items, position, area, cube, radius, trajectory, and corridor query types. Returns 'CoverageJSON' as tidy 'tibble' rows and 'GeoJSON' as 'sf' objects. |
| License: | MIT + file LICENSE |
| URL: | https://github.com/ksonda/edr4r |
| BugReports: | https://github.com/ksonda/edr4r/issues |
| Encoding: | UTF-8 |
| Depends: | R (≥ 4.1) |
| Imports: | cli, httr2 (≥ 1.1.0), jsonlite, purrr, rlang, tibble, vctrs |
| Suggests: | base64enc, ggplot2, htmlwidgets, knitr, leaflet, rmarkdown, sf, svglite, testthat (≥ 3.0.0), webfakes |
| Config/testthat/edition: | 3 |
| RoxygenNote: | 7.3.3 |
| VignetteBuilder: | knitr |
| NeedsCompilation: | no |
| Packaged: | 2026-07-10 01:53:14 UTC; konda |
| Author: | Kyle Onda [aut, cre, cph] |
| Maintainer: | Kyle Onda <konda@lincolninst.edu> |
| Repository: | CRAN |
| Date/Publication: | 2026-07-10 07:30:30 UTC |
edr4r: A tidy R client for OGC API - Environmental Data Retrieval
Description
edr4r talks to any service that implements
OGC API - Environmental Data Retrieval.
It's general-purpose, but most of the testing and real-world use to
date has been against in-situ monitoring networks – the kind of
service that exposes stream gauges, weather stations, snow telemetry,
or reservoir telemetry as EDR collections.
Details
Two operational endpoints worth pointing it at:
-
Western Water Datahub (a pygeoapi deployment)
The Met Office Labs EDR demonstrator is also useful for cross-server compatibility experiments. It is a technical demonstrator, not an operational service, so its availability and advertised data may change without notice.
A typical session looks like:
Build a client with
edr_client().Discover what's on offer with
edr_collections()andedr_queryables().Pull data with
edr_locations()/edr_location(),edr_cube(),edr_area(),edr_position(), or the less commonedr_radius()/edr_trajectory()/edr_corridor().Flatten the response with
covjson_to_tibble()(for CoverageJSON) orgeojson_to_sf()(for GeoJSON).
For everything the high-level verbs don't cover, edr_request() is
the raw escape hatch.
Author(s)
Maintainer: Kyle Onda konda@lincolninst.edu [copyright holder]
See Also
Useful links:
Convert a CoverageJSON response to a tidy tibble
Description
Flattens a CoverageJSON Coverage or CoverageCollection into a
long tibble with one row per (coverage, parameter, domain position).
Handles primitive, regularly spaced, and composite tuple axes, including
the axes used by Grid, PointSeries, MultiPointSeries, and Trajectory
domains. Inline NdArray ranges are validated before they are flattened.
Usage
covjson_to_tibble(x, datetime_as_posix = TRUE)
Arguments
x |
A CoverageJSON object: either an |
datetime_as_posix |
If |
Value
A tibble with columns coverage_id, parameter,
parameter_label, unit, datetime, x, y, z, and value.
Columns that are absent from the source are filled with NA.
Area query (data inside a polygon)
Description
Calls GET /collections/{collection_id}/area with a WKT POLYGON in
the coords parameter.
Usage
edr_area(
client,
collection_id,
coords,
datetime = NULL,
parameter_name = NULL,
z = NULL,
crs = NULL,
format = c("covjson", "json"),
...
)
Arguments
client |
An |
collection_id |
Collection identifier. |
coords |
WKT polygon string, or a matrix / data.frame of
|
datetime |
ISO-8601 instant or interval, e.g.
|
parameter_name |
Character vector of parameter names to filter
on. Sent as a comma-separated |
z |
Vertical level filter. |
crs |
Optional CRS URI for the response. |
format |
|
... |
Additional query parameters passed through verbatim. |
Value
An edr_response containing the server's CoverageJSON response.
Convert it with covjson_to_tibble().
Create an EDR client
Description
Builds a reusable client object that captures the base URL of an OGC API - EDR service, a default user-agent, and HTTP options that are applied to every request.
Usage
edr_client(
base_url,
user_agent = NULL,
timeout = 60,
max_tries = 3,
retry_on_failure = TRUE,
headers = NULL,
verbose = FALSE
)
Arguments
base_url |
Base URL of an
OGC API - EDR service. Examples:
the USGS waterdata OGC API
at |
user_agent |
String sent in the |
timeout |
Request timeout in seconds. Defaults to 60. |
max_tries |
Maximum number of attempts per request. The client retries on 408, 429, and 5xx responses with exponential backoff. Defaults to 3. |
retry_on_failure |
If |
headers |
Named character vector of extra headers attached to
every request (e.g. |
verbose |
If |
Value
An object of class edr_client.
Examples
usgs <- edr_client("https://api.waterdata.usgs.gov/ogcapi/beta")
usgs
Get a single collection's metadata
Description
Get a single collection's metadata
Usage
edr_collection(client, collection_id)
Arguments
client |
An |
collection_id |
Collection identifier as advertised by the
server – e.g. |
Value
A list with the raw collection document.
List collections offered by the service
Description
List collections offered by the service
Usage
edr_collections(client)
Arguments
client |
An |
Value
A tibble with one row per collection. Always includes id,
title, description, extent_bbox, crs, data_queries, and
links columns.
Declared OGC API conformance classes
Description
Declared OGC API conformance classes
Usage
edr_conformance(client)
Arguments
client |
An |
Value
A character vector of conformance class URIs.
Corridor query (data along a path with a width)
Description
Calls GET /collections/{collection_id}/corridor.
Usage
edr_corridor(
client,
collection_id,
coords,
corridor_width,
corridor_height,
width_units = "km",
height_units = "m",
datetime = NULL,
parameter_name = NULL,
z = NULL,
crs = NULL,
format = c("covjson", "json"),
...
)
Arguments
client |
An |
collection_id |
Collection identifier. |
coords |
WKT LINESTRING, a matrix / data.frame of |
corridor_width |
Width of the corridor. |
corridor_height |
Vertical extent of the corridor. Required by the EDR corridor query requirements. |
width_units |
Units for |
height_units |
Units for |
datetime |
ISO-8601 instant or interval, e.g.
|
parameter_name |
Character vector of parameter names to filter
on. Sent as a comma-separated |
z |
Vertical level filter. |
crs |
Optional CRS URI for the response. |
format |
|
... |
Additional query parameters passed through verbatim. |
Value
An edr_response containing the server's CoverageJSON response.
Convert it with covjson_to_tibble().
Cube query (data inside a bounding box)
Description
Calls GET /collections/{collection_id}/cube with a bounding box.
Usage
edr_cube(
client,
collection_id,
bbox,
datetime = NULL,
parameter_name = NULL,
z = NULL,
crs = NULL,
format = c("covjson", "json"),
...
)
Arguments
client |
An |
collection_id |
Collection identifier. |
bbox |
Numeric vector of length 4 or 6. |
datetime |
ISO-8601 instant or interval, e.g.
|
parameter_name |
Character vector of parameter names to filter
on. Sent as a comma-separated |
z |
Vertical level filter. |
crs |
Optional CRS URI for the response. |
format |
|
... |
Additional query parameters passed through verbatim. |
Value
An edr_response containing the server's CoverageJSON response.
Convert it with covjson_to_tibble().
One-shot fetch + plot + map for a collection
Description
Convenience wrapper that plans a supported query, fetches data with
one bulk request via edr_cube() or edr_area() when possible,
and hands the result to edr_map() or edr_plot(). Station locations
are requested only when the result needs a station map or a per-location
fallback. Optionally writes a map to a self-contained HTML file.
Usage
edr_explore(
client,
collection_id,
bbox = NULL,
coords = NULL,
datetime = NULL,
parameter_name = NULL,
limit = NULL,
record_limit = NULL,
max_requests = 100L,
file = NULL,
popup = "plot+csv",
method = c("auto", "cube", "area", "position", "per-location"),
output = c("auto", "map", "plot", "data"),
plot_view = c("auto", "time", "profile", "grid"),
quiet = FALSE,
...
)
Arguments
client |
An |
collection_id |
Collection identifier. |
bbox |
Optional numeric length-4 bbox. Used both to filter
the locations index (if the server honours it) and as the bbox
for the cube fetch in |
coords |
Point coords for |
datetime |
ISO-8601 interval forwarded to the data fetch. |
parameter_name |
Character vector of parameter ids; forwarded
to the data fetch. Use |
limit |
Optional cap on the number of stations to map. |
record_limit |
Optional per-station record cap, passed through
to |
max_requests |
Maximum number of per-location data requests permitted
in one call. Defaults to 100. Set to |
file |
If non- |
popup |
Popup mode (forwarded to |
method |
One of |
output |
One of |
plot_view |
Plot view passed to |
quiet |
If |
... |
Forwarded to |
Details
The default method = "auto" picks the cheapest route the
collection advertises in its data_queries:
-
cube – one HTTP call returning a CoverageCollection across the whole bbox. Fast. Used when the collection supports
cubeand abboxis supplied. -
area – like cube but uses a polygon. Used when
coordsis supplied and the collection supportsarea. -
position – one HTTP call at a point. Useful for vertical profiles returned by position queries.
-
per-location – the fallback: one HTTP call per station via
edr_location(). Slower (N+1), used when neither spatial bulk query is supported or the matching spatial input was not supplied.
Force a specific path by setting method. coords is required for
area and position; if method = "cube" and bbox is omitted,
the bbox is derived from the returned locations.
Value
A leaflet htmlwidget, a ggplot, a tidy tibble/list when
output = "data", or invisible(file) when a map is saved.
Examples
## Not run:
cl <- edr_client("https://api.wwdh.internetofwater.app")
# One /cube call across a bbox -- fast.
edr_explore(
cl, "rise-edr",
bbox = c(-116, 35.5, -114, 36.5),
datetime = "2023-01-01/2023-03-31",
parameter_name = "3",
file = tempfile(fileext = ".html")
)
## End(Not run)
Items (OGC API Features) helpers
Description
Many EDR servers expose an OGC API Features /items endpoint
alongside the EDR queries. Behaviour varies: some deployments
implement items as a full Features endpoint, others as a thin stub
used only to register the collection as both EDR and Features. In
the stub case, non-trivial data is usually obtained via the EDR
queries (edr_locations(), edr_area(), edr_cube(), etc.).
Usage
edr_items(
client,
collection_id,
bbox = NULL,
datetime = NULL,
limit = NULL,
format = c("geojson", "json"),
...
)
edr_item(client, collection_id, item_id, format = c("geojson", "json"), ...)
Arguments
client |
An |
collection_id |
Collection identifier. |
bbox |
Numeric vector of length 4 or 6
( |
datetime |
ISO-8601 instant or interval, e.g.
|
limit |
Maximum number of features to return. |
format |
|
... |
Additional query parameters passed through verbatim. |
item_id |
Identifier of a single feature. |
Value
An sf object when sf is installed and the server returns
GeoJSON; otherwise an edr_response wrapping the GeoJSON document.
EDR service landing page
Description
Retrieves the service root document, which advertises links to the collections, conformance, and openapi endpoints.
Usage
edr_landing(client)
Arguments
client |
An |
Value
A list with the parsed landing document.
Get data for a single location
Description
Calls GET /collections/{collection_id}/locations/{location_id}.
Typically returns CoverageJSON; pass the result to
covjson_to_tibble() for a tidy data frame.
Usage
edr_location(
client,
collection_id,
location_id,
datetime = NULL,
parameter_name = NULL,
z = NULL,
crs = NULL,
format = c("covjson", "geojson", "csv", "json"),
...
)
Arguments
client |
An |
collection_id |
Collection identifier. |
location_id |
Identifier of the location, as advertised by the
server. IDs vary by deployment: bare integers, alphanumeric station
codes, or compound identifiers (e.g. colon-separated triplets used
by some snow / forecast networks). Reserved characters are
URL-encoded for you; a literal |
datetime |
ISO-8601 instant or interval, e.g.
|
parameter_name |
Character vector of parameter names to filter
on. Sent as a comma-separated |
z |
Vertical level filter. |
crs |
Optional CRS URI for the response. |
format |
|
... |
Additional query parameters passed through verbatim. |
Value
An edr_response containing CoverageJSON or GeoJSON, or a tibble
for CSV responses. Use covjson_to_tibble() or geojson_to_sf() to
convert structured JSON responses.
List locations in a collection
Description
Calls GET /collections/{collection_id}/locations. With no extra
filters, EDR servers typically return a GeoJSON FeatureCollection
of available locations.
Usage
edr_locations(
client,
collection_id,
bbox = NULL,
datetime = NULL,
parameter_name = NULL,
crs = NULL,
limit = NULL,
format = c("geojson", "json"),
...
)
Arguments
client |
An |
collection_id |
Collection identifier. |
bbox |
Numeric vector of length 4 or 6
( |
datetime |
ISO-8601 instant or interval, e.g.
|
parameter_name |
Character vector of parameter names to filter
on. Sent as a comma-separated |
crs |
Optional CRS URI for the response. |
limit |
Maximum number of features to return. |
format |
|
... |
Additional query parameters passed through verbatim. |
Value
When the server returns GeoJSON, an sf object if the sf
package is installed, otherwise an edr_response wrapping the raw
GeoJSON. When the server returns CoverageJSON, an edr_response.
Map EDR locations or coverage data
Description
Builds a leaflet::leaflet map of station features or gridded/profile CoverageJSON data. Station maps can show per-station popups with interactive time-series charts and CSV downloads. Coverage maps keep all supplied parameters, times, and vertical levels in the widget and expose in-map controls for choosing the active slice; grid cells open popups with a time-series chart for the clicked cell.
Usage
edr_map(
locations,
data = NULL,
popup = c("plot+csv", "plot", "csv", "table", "all"),
location_col = "coverage_id",
id_col = NULL,
label_col = NULL,
parameter = NULL,
plot_width = 7,
plot_height = 3.5,
plot_dpi = 72,
tile_provider = "CartoDB.Positron",
marker_radius = 6,
matched_color = "#2C7FB8",
unmatched_color = "#BBBBBB",
show_unmatched = TRUE,
legend = TRUE,
max_match_distance = NULL,
mode = c("auto", "stations", "grid", "profile"),
controls = TRUE,
initial = list(),
grid_opacity = 0.75
)
Arguments
locations |
An |
data |
See above. Defaults to |
popup |
One of |
location_col |
Column in |
id_col |
Column in |
label_col |
Column in |
parameter |
Optional character vector restricting which parameters are displayed. On station maps, the filtered rows also determine whether a station is marked as having data. On coverage maps, only matching rows are included in the widget payload. |
plot_width, plot_height |
Popup chart dimensions in inches.
Display size in pixels is |
plot_dpi |
Display dots-per-inch for popup charts. Default 72; bump to 90+ if popups look small on hi-DPI displays. |
tile_provider |
Leaflet basemap. Default |
marker_radius |
Marker radius in pixels for stations that have time-series data. Data-less stations are drawn one pixel smaller. |
matched_color |
Marker colour for stations that joined to a
coverage in |
unmatched_color |
Marker colour for stations without data
(only relevant when |
show_unmatched |
If |
legend |
If |
max_match_distance |
Optional maximum coordinate distance for
spatially matching |
mode |
Map mode. |
controls |
If |
initial |
Named list of initial coverage-map selections, e.g.
|
grid_opacity |
Fill opacity for gridded coverage cells. |
Details
data can be one of:
-
NULL– just markers with the sf attribute table as a popup (whenpopup = "table"orpopup = "all"). A long tibble (the output of
covjson_to_tibble()) with one column matching the locations' id column. Setlocation_col =to the column indatathat holds the location id andid_col =to the column inlocations.A named list of tibbles, keyed by feature id. This is what
edr_explore()passes when it fetches one time series per station — and the right shape when each station has its own CovJSON response, because server-assignedcoverage_ids like"1"won't naturally match the feature id.
Value
A leaflet htmlwidget. Pass it to edr_save_html() to
write a selfcontained HTML file.
List the data parameters a collection serves
Description
Pulls the parameter_names block out of the collection document
(GET /collections/{id}) and flattens it into a tidy tibble. These
are the observed properties you can pass to parameter_name = on the
query verbs (edr_location(), edr_cube(), etc.).
Usage
edr_parameters(client, collection_id)
Arguments
client |
An |
collection_id |
Collection identifier as advertised by the
server – e.g. |
Details
EDR servers vary in how they key the parameter_names dictionary
(numeric IDs, short codes, etc.). The id column in the returned
tibble is the value to pass back as parameter_name; the name
column is the human-readable label.
Value
A tibble with one row per parameter. Columns:
id, name, description, unit_symbol, unit_label,
observed_property.
Plot an EDR response as a ggplot
Description
Convenience wrapper around ggplot2::ggplot() for the long tibble
returned by covjson_to_tibble(). Automatically chooses a sensible
view for time series, vertical profiles, and x/y grids.
Usage
edr_plot(
data,
parameter = NULL,
group = "coverage_id",
facet = "parameter",
scales = "free_y",
geom = c("line", "point", "both"),
facet_labels = TRUE,
view = c("auto", "time", "profile", "grid")
)
Arguments
data |
Either a tidy tibble from |
parameter |
Optional character vector restricting to a subset of parameters. |
group |
Column in |
facet |
Column to facet by. Defaults to |
scales |
|
geom |
One of |
facet_labels |
If |
view |
Plot view. |
Value
A ggplot object.
Examples
## Not run:
cl <- edr_client("https://api.wwdh.internetofwater.app")
resp <- edr_location(cl, "rise-edr",
location_id = 3514,
datetime = "2023-01-01/2023-06-30",
parameter_name = "3")
edr_plot(resp)
## End(Not run)
Position query (data at a point)
Description
Calls GET /collections/{collection_id}/position with a WKT POINT
in the coords parameter.
Usage
edr_position(
client,
collection_id,
coords,
datetime = NULL,
parameter_name = NULL,
z = NULL,
crs = NULL,
format = c("covjson", "json"),
...
)
Arguments
client |
An |
collection_id |
Collection identifier. |
coords |
Either a length-2 numeric vector |
datetime |
ISO-8601 instant or interval, e.g.
|
parameter_name |
Character vector of parameter names to filter
on. Sent as a comma-separated |
z |
Vertical level filter. |
crs |
Optional CRS URI for the response. |
format |
|
... |
Additional query parameters passed through verbatim. |
Value
An edr_response containing the server's CoverageJSON response.
Convert it with covjson_to_tibble().
Get the queryables (filter properties) for a collection
Description
Returns the OGC API queryables document for a collection – a JSON
Schema describing the filter properties the server exposes (this is
typically used by OGC API Features for CQL2 / property-based
filtering). It is not the right place to look up the data
parameters / observed properties an EDR collection serves; for that,
use edr_parameters().
Usage
edr_queryables(client, collection_id)
Arguments
client |
An |
collection_id |
Collection identifier as advertised by the
server – e.g. |
Value
A list with the parsed queryables document.
Radius query (data within a radius of a point)
Description
Calls GET /collections/{collection_id}/radius.
Usage
edr_radius(
client,
collection_id,
coords,
within,
within_units = "km",
datetime = NULL,
parameter_name = NULL,
z = NULL,
crs = NULL,
format = c("covjson", "json"),
...
)
Arguments
client |
An |
collection_id |
Collection identifier. |
coords |
Either a length-2 numeric vector |
within |
Radius value. |
within_units |
Units of |
datetime |
ISO-8601 instant or interval, e.g.
|
parameter_name |
Character vector of parameter names to filter
on. Sent as a comma-separated |
z |
Vertical level filter. |
crs |
Optional CRS URI for the response. |
format |
|
... |
Additional query parameters passed through verbatim. |
Value
An edr_response containing the server's CoverageJSON response.
Convert it with covjson_to_tibble().
Perform a low-level EDR request
Description
Generally you should not need to call this directly: the high-level
verbs (edr_locations(), edr_area(), etc.) build the path and
query string for you. Use edr_request() when you need to hit a
bespoke path or a non-standard parameter.
Usage
edr_request(
client,
path,
query = list(),
format = c("json", "geojson", "covjson", "csv", "html", "raw"),
parse = TRUE
)
Arguments
client |
An |
path |
Path under the base URL (with or without leading slash),
e.g. |
query |
Named list of query parameters. Values may be scalars
or vectors; vectors are joined with |
format |
Response format: one of |
parse |
If |
Value
A parsed list, tibble, or edr_response wrapper; an
httr2_response when parse = FALSE; or a typed empty result for HTTP
204 responses.
Save a map to a standalone HTML file
Description
Thin wrapper around htmlwidgets::saveWidget() for the leaflet
map returned by edr_map() or edr_explore(). With
selfcontained = TRUE (the default), popup chart data and CSV
download links live inside the file – no sidecar directory.
Usage
edr_save_html(map, file, selfcontained = TRUE, ...)
Arguments
map |
A |
file |
Path to write to. |
selfcontained |
If |
... |
Forwarded to |
Value
Invisibly returns file.
Trajectory query (data along a path)
Description
Calls GET /collections/{collection_id}/trajectory.
Usage
edr_trajectory(
client,
collection_id,
coords,
datetime = NULL,
parameter_name = NULL,
z = NULL,
crs = NULL,
format = c("covjson", "json"),
...
)
Arguments
client |
An |
collection_id |
Collection identifier. |
coords |
WKT LINESTRING, a matrix / data.frame of |
datetime |
ISO-8601 instant or interval, e.g.
|
parameter_name |
Character vector of parameter names to filter
on. Sent as a comma-separated |
z |
Vertical level filter. |
crs |
Optional CRS URI for the response. |
format |
|
... |
Additional query parameters passed through verbatim. |
Value
An edr_response containing the server's CoverageJSON response.
Convert it with covjson_to_tibble().
Convert a GeoJSON EDR response to an sf object
Description
Convert a GeoJSON EDR response to an sf object
Usage
geojson_to_sf(x)
Arguments
x |
An |
Value
An sf object. Requires the sf package. If sf is not
installed, returns a tibble of feature properties (without geometry)
and warns.