API Example Using R
# This data frame contains the coordinate pairs for the vertices of the polygon
# for an AOI. You can get an equivalent data frame from an sf polygon object
# using sf::st_coordinates(). Note that the first and last coordinates are
# identical in order to close the polygon.
aoi_vertex_coords <- data.frame(X = c(-106.416024,
-106.157845,
-106.146859,
-106.328133,
-106.388558,
-106.454476,
-106.416024),
Y = c(44.086577,
44.228451,
44.471990,
44.417086,
44.318914,
44.193015,
44.086577))
# This creates the coordinate strings formatted for use in a geoJSON using the
# data frame of coordinates. The expected format for a coordinate pair is
# "[-106.454476,44.193015]". This could be achieved with an apply() but using
# mutate() from the package dplyr is more readable.
aoi_vertex_coords <- dplyr::mutate(.data = aoi_vertex_coords,
# This creates a new variable with the strings
# for each row.
coordinate_string = paste0("[", X, ",", Y, "]"))
# These are the pieces of the geoJSON string that go before and after the
# coordinates. In the postcoordinate string, you may define "mask" as true to
# ignore cropland, development, and open water or false to include those.
# Note that in order for this to work, the strings defining the geoJSON *must*
# use quotation marks internally, so the strings themselves need to be wrapped
# in aprostrophes, e.g. '{"type":"Feature"}' and not "{'type':'Feature'}".
geojson_precoordinate_string <-'{"type":"Feature",
"geometry": {"geodesic":false,
"type":"Polygon",
"coordinates":[['
geojson_postcoordinate_string <- ']]},
"properties": {"mask":true,
"year":null}
}'
# The components can be assembled into a single geoJSON string.
# The coordinate strings in the data frame need to be collapsed into a single
# string where each pair is separated by a comma.
aoi_geojson <- paste0(geojson_precoordinate_string,
paste(aoi_vertex_coords[["coordinate_string"]],
collapse = ","),
geojson_postcoordinate_string)
# Using httr::RETRY() will let R make multiple attempts to retrieve the data
# before giving up. Importantly, the verb argument must be "POST", the URL must
# point to the correct API endpoint for the data you want, config should at
# least specify that the desired return format is JSON, and the body argument
# needs to be the geoJSON string constructed for the AOI.
rap_json <- httr::RETRY(verb = "POST",
url = "https://us-central1-rap-data-365417.cloudfunctions.net/production16dayV3",
config = httr::content_type_json(),
body = aoi_geojson)
# httr::content() will convert the returned JSON into more conventional R
# objects: nested lists containing the various kinds of values in the JSON.
rap_obj <- httr::content(x = rap_json,
as = "parsed")
# The returned and parsed object will be a list. One of the values in the list
# will be another list named "properties" which contains yet another list of
# each of the rows in the returned dataset, including the variable names as the
# first vector in the list. In this case, the data are for 16-day production.
returned_data_raw_list <- rap_obj$properties$production16day
# There's no "correct" way way to convert the list into a data frame. One of the
# more straightforward is by turning each list of values in the list into a
# data frame then combining those with dplyr:bind_rows().
returned_data_raw_list <- lapply(X = returned_data_raw_list[2:length(returned_data_raw_list)],
variable_names = returned_data_raw_list[[1]],
FUN = function(X, variable_names){
# The current values need the variable names,
# so this makes sure that variable_names is a
# vector before assigning them to the current
# row's values which are called X within the
# lapply().
names(X) <- unlist(variable_names)
# Make a wide-format data frame out of the
# current values by binding them column-wise
# which results in a single data frame with
# correctly-named variables thanks to the
# naming of X above.
dplyr::bind_cols(X)
})
returned_data_raw_dataframe <- dplyr::bind_rows(returned_data_raw_list)
# The data returned will include some values that need to be adjusted before
# using, which can be accomplished with dplyr::mutate().
returned_data <- dplyr::mutate(.data = returned_data_raw_dataframe,
# Convert the date from a character string to a
# value of class "date".
date = as.Date(date),
# Make sure the year is numeric because it may be
# a character string.
year = as.numeric(year),
# Make sure the day of the year is also numeric
# and adjust so that the highest value is 365 and
# not 366.
doy = as.numeric(doy) - 1,
# The rest of the variables should be numeric and
# rounded to 3 decimal places. Additionally, any
# values of -99 should be considered NA values.
# Using dplyr::across() here applies the
# replacement, conversion, and rounding to all
# variables after the first three, i.e., after
# date, year, and doy.
dplyr::across(.cols = -c(1:3),
.fns = ~ replace(x = .x,
list = .x == -99,
values = NA) |>
as.numeric(x = _) |>
round(x = _,
digits = 3)))