edr4r is a small, tidy client for any service that
speaks OGC API - Environmental
Data Retrieval. Most of the real-world use to date has been against
in-situ monitoring networks – stream gauges, weather stations, snow
telemetry, reservoir telemetry – but the package itself is generic.
Two example endpoints you can point it at right now:
The Met Office Labs EDR demonstrator is another useful endpoint for cross-server experiments. It is a technical demonstrator, not an operational service: its availability, collections, and response details may change without notice, so it should not be used as a production dependency.
This vignette uses the Western Water Datahub’s rise-edr
collection as one real endpoint for demonstrating the core
edr4r workflow. WWDH dataset notes, raw HTTP walkthroughs,
and presentation material live in the standalone WWDH EDR docs. The
USGS example lives in its own article,
vignette("usgs-streamgages").
Install the released version from CRAN:
or the development version from GitHub with pak:
library(edr4r)
library(ggplot2)
client <- edr_client("https://api.wwdh.internetofwater.app")
client
#> <edr_client>
#> base_url: <https://api.wwdh.internetofwater.app>
#> user_agent: edr4r/0.1.0 (+https://github.com/ksonda/edr4r)
#> timeout: 60s
#> max_tries: 3The client just stores connection settings (base URL, user agent,
timeout, retry policy). Pass verbose = TRUE to echo every
request URL, or headers = to attach auth tokens.
A small terrain lookup is a low-cost way to exercise the non-operational Met Office demonstrator without downloading forecast data:
met_client <- edr_client(
"https://labs.metoffice.gov.uk/edr",
timeout = 10,
max_tries = 1
)
terrain <- edr_position(
met_client,
"terrain_tiles",
coords = c(-0.1276, 51.5072),
parameter_name = "Height"
)
covjson_to_tibble(terrain)Because the endpoint is explicitly experimental, this request is not
run when the vignette is built or during R CMD check. The
repository exercises it separately in a scheduled, non-blocking live
smoke check.
edr_collections() lists every EDR collection the service
serves.
collections <- edr_collections(client)
collections[, c("id", "title", "data_queries")]
#> # A tibble: 35 × 3
#> id title data_queries
#> <chr> <chr> <list>
#> 1 rise-edr USBR Reclamation Information Sharing Environ… <chr [4]>
#> 2 snotel-edr USDA Snowpack Telemetry Network (SNOTEL) <chr [4]>
#> 3 awdb-forecasts-edr USDA Air and Water Database (AWDB) Forecasts <chr [4]>
#> 4 snotel-huc06-means USDA Snotel Snow Water Equivalent Aggregated… <NULL>
#> 5 usace-edr USACE Access2Water API <chr [4]>
#> 6 noaa-qpf-day-1 NOAA Weather Prediction Center Quantitative … <NULL>
#> 7 noaa-qpf-day-2 NOAA Weather Prediction Center Quantitative … <NULL>
#> 8 noaa-qpf-day-3 NOAA Weather Prediction Center Quantitative … <NULL>
#> 9 noaa-qpf-day-4-5 NOAA Weather Prediction Center Quantitative … <NULL>
#> 10 noaa-qpf-day-6-7 NOAA Weather Prediction Center Quantitative … <NULL>
#> # ℹ 25 more rowsThe data_queries column tells you which EDR query types
each collection supports (locations, cube,
area, …). Hit a verb the server doesn’t implement and you
get an HTTP error.
To see the data parameters a collection exposes (the values you can
pass to parameter_name = on the query verbs), use
edr_parameters():
params <- edr_parameters(client, "rise-edr")
nrow(params)
#> [1] 782
head(params[, c("id", "name", "unit_symbol")])
#> # A tibble: 6 × 3
#> id name unit_symbol
#> <chr> <chr> <chr>
#> 1 1835 Secondary Canal Stage ft
#> 2 1834 Lake/Reservoir Elevation ft
#> 3 1830 Lake/Reservoir Release - Total cfs
#> 4 1818 Total Dissolved Gas (TDG) %
#> 5 1817 Growing Degree Days (50 Degree Base Temperature) GDD
#> 6 1816 Calculated Unregulated Flow tafedr_queryables() is something different – it returns the
OGC queryables JSON Schema (filter properties for CQL2 / OGC API
Features). For discovering parameter names,
edr_parameters() is what you want.
With no filters, edr_locations() returns the station
index as a GeoJSON FeatureCollection, promoted to an
sf object when sf is
installed:
stations <- edr_locations(client, "rise-edr")
nrow(stations)
#> [1] 926
head(stations[, c("_id", "locationName")])
#> Simple feature collection with 6 features and 2 fields
#> Geometry type: POINT
#> Dimension: XY
#> Bounding box: xmin: -122.474 ymin: 32.8834 xmax: -101.2656 ymax: 48.2667
#> Geodetic CRS: WGS 84
#> # A tibble: 6 × 3
#> `_id` locationName geometry
#> <int> <chr> <POINT [°]>
#> 1 1 Marys Lake (-105.5343 40.34408)
#> 2 2 Audubon Lake North Dakota (-101.2656 47.6114)
#> 3 3 Gray Reef Reservoir and Dam (-106.6989 42.5656)
#> 4 5 Lake Frances Reservoir (-112.2 48.2667)
#> 5 6 Spring Creek Reservoir and Debris Dam (-122.474 40.629)
#> 6 7 Imperial Reservoir at Imperial Dam (-114.4676 32.8834)The WWDH rise-edr locations index uses _id
as the identifier column, not id. That’s fine – the query
verbs accept either, and edr_map() will auto-detect.
Pick a known station (Lake Mead, _id 3514) and a
parameter (3, Daily Reservoir Storage) and you get
CoverageJSON back. Flatten it with covjson_to_tibble():
resp <- edr_location(
client, "rise-edr",
location_id = 3514,
datetime = "2023-01-01/2023-06-30",
parameter_name = "3"
)
df <- covjson_to_tibble(resp)
head(df)
#> # A tibble: 6 × 9
#> coverage_id parameter parameter_label unit datetime x y
#> <chr> <chr> <chr> <chr> <dttm> <dbl> <dbl>
#> 1 1 3 Lake/Reservoir St… af 2023-01-01 07:00:00 -115. 36.0
#> 2 1 3 Lake/Reservoir St… af 2023-01-02 07:00:00 -115. 36.0
#> 3 1 3 Lake/Reservoir St… af 2023-01-03 07:00:00 -115. 36.0
#> 4 1 3 Lake/Reservoir St… af 2023-01-04 07:00:00 -115. 36.0
#> 5 1 3 Lake/Reservoir St… af 2023-01-05 07:00:00 -115. 36.0
#> 6 1 3 Lake/Reservoir St… af 2023-01-06 07:00:00 -115. 36.0
#> # ℹ 2 more variables: z <dbl>, value <dbl>edr_plot() is a small ggplot2 wrapper for
the tidy tibble:
plot of chunk plot-lake-mead
Faceted by parameter (so different units don’t share a y-axis) and coloured by station. Add layers or themes like any other ggplot.
For collections that support cube,
edr_explore() fetches every station’s data in
one bulk request and renders the map with per-station
popups – much faster than fetching one station at a time.
rise-edr advertises cube, so the default
method = "auto" takes that path.
m <- edr_explore(
client, "rise-edr",
bbox = c(-114, 32, -111, 38), # SW US
datetime = "2023-01-01/2023-06-30",
parameter_name = "3",
popup = "plot+csv",
label_col = "locationName",
quiet = TRUE
)The object prints as an interactive leaflet map in an R session; each blue marker opens the larger plot/CSV popup for the station.
Markers with data are blue (clickable popup with plot + CSV); stations the bbox covers that returned no data for the requested parameter/window are dimmed grey. A legend in the bottom-right explains the distinction.
Save the same map to standalone HTML (selfcontained, no sidecar directory):
datetime is forgiving: pass "start/end",
an open interval like "2020-01-01/..", or a length-2
character vector. It gets normalised into the ISO-8601 form the server
expects.parameter_name is a character vector. It’s sent as one
comma-separated parameter-name query parameter."1185:CO:SNTL" show up in snow and forecast
networks). Those work as-is – reserved characters get URL-encoded for
you. A literal / in an ID is rejected, because it can’t
survive a round trip through HTTP path segments no matter how you encode
it.locations,
position, cube, and area are
common; radius, trajectory, and
corridor less so. The client supports them all per the spec, but a call against a
collection that doesn’t implement a given verb returns an HTTP
error.vignette("usgs-streamgages") – a walk-through against
the USGS waterdata endpoint, which only advertises
locations (so the per-station fallback kicks in).