Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Convert observational data functions from httr to httr2 #49

Merged
merged 25 commits into from
Dec 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
5d31890
convert npn_stations() to use httr2
Aariq Nov 20, 2024
218e98e
convert npn_stations_by_location() to use httr2
Aariq Nov 20, 2024
566c235
error if state isn't valid (rlang is "free" dependency)
Aariq Nov 20, 2024
3d800fd
regenerate fixtures
Aariq Nov 20, 2024
3fdcd89
convert npn_stations_with_spp() to use httr2
Aariq Nov 20, 2024
4b5706a
... unused
Aariq Nov 20, 2024
f752ab7
merge main
Aariq Nov 20, 2024
1bab4da
convert phenophases functions to httr2
Aariq Nov 20, 2024
ba116df
use util function to generate queries
Aariq Nov 20, 2024
fa892c9
convert npn_phenophases_by_species to use httr2
Aariq Nov 20, 2024
c68988c
switch npn_get_phenophases_for_taxon to httr2
Aariq Nov 20, 2024
06d9800
switch npn_abundance_categories to httr2
Aariq Nov 20, 2024
c016cda
convert npn_stations_by_state to use httr2
Aariq Nov 20, 2024
d88c048
convert npn_groups to use httr2
Aariq Nov 20, 2024
3c8e420
document()
Aariq Nov 20, 2024
1236ead
convert npn_get_species.R to use httr2
Aariq Nov 20, 2024
9579a91
convert npn_datasets to use httr2
Aariq Nov 20, 2024
77909b6
comment out unused funs
Aariq Nov 20, 2024
8fb40d5
update news
Aariq Nov 20, 2024
6e6babf
revert npn_species_* to old behavior and save input validation for a …
Aariq Nov 26, 2024
4ec490b
update NEWS
Aariq Nov 26, 2024
b077a84
remove unused util funs
Aariq Nov 26, 2024
f6d4b99
document()
Aariq Nov 26, 2024
568850d
Merge branch 'master' into httr2
Aariq Dec 3, 2024
93a1496
different way of exploding multiple query values
Aariq Dec 10, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .Rbuildignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,6 @@ cran-comments.md
^CRAN-SUBMISSION$
^codecov\.yml$
^LICENSE\.md$
notes/
^_pkgdown\.yml$
^pkgdown$
6 changes: 4 additions & 2 deletions DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,11 @@ Imports:
tibble,
curl,
raster,
plyr,
XML,
magrittr
magrittr,
httr2,
dplyr,
rlang
Suggests:
ggplot2,
testthat,
Expand Down
1 change: 0 additions & 1 deletion NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ importFrom(httr,content)
importFrom(httr,stop_for_status)
importFrom(jsonlite,fromJSON)
importFrom(magrittr,"%>%")
importFrom(plyr,rbind.fill)
importFrom(utils,URLencode)
importFrom(utils,download.file)
importFrom(utils,object.size)
Expand Down
9 changes: 9 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
# rnpn (development version)

* `npn_phenophase_details()` now takes a vector of phenophase IDs rather than a list
* Functions that previously returned `data.frame` objects now return tibbles. Where they previously returned `NULL` on errors, they now return empty 0x0 tibbles.
* `npn_get_phenophases_for_taxon()` now returns a tibble rather than a list.
* Documented a behavior of `npn_species_type()` where setting `kingdom` to `NULL` returns results for *both* `Plantae` and `Animalia`.
* Missing values returned by `npn_stations_by_state()` previously returned as the string `"emptyvalue"` are now returned as `NA`s.
* `rnpn` now has `dplyr` as a dependency instead of `plyr`
* `rnpn` now uses `httr2` instead of `httr` internally for functions that get observational data
* `...` is no longer used for functions that get observational data

# rnpn 1.2.9 (2024-08-18)

### NEW FEATURES
Expand Down
21 changes: 11 additions & 10 deletions R/npn_dataset.R
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@



#' Get Datasets
#'
#' Returns a complete list of information about all datasets integrated into the NPN
#' dataset. Data can then be pulled for individual datasets using their unique IDs.
#' Returns a complete list of information about all datasets integrated into the
#' NPN dataset. Data can then be pulled for individual datasets using their
#' unique IDs.
#' @export
#' @template curl
#' @return data.frame of datasets and their IDs.
#' @param ... Currently unused.
#' @return tibble of datasets and their IDs.
#' @examples \dontrun{
#' npn_datasets()
#' }
npn_datasets <- function(...) {
tibble::as_tibble(
npn_GET(paste0(base(), 'observations/getDatasetDetails.json'), list(), TRUE, ...)
)
req <- base_req %>%
httr2::req_url_path_append('observations/getDatasetDetails.json')
resp <- httr2::req_perform(req)
out <- httr2::resp_body_json(resp, simplifyVector = TRUE)
#return
tibble::as_tibble(out)
}
165 changes: 105 additions & 60 deletions R/npn_get_species.R
Original file line number Diff line number Diff line change
@@ -1,35 +1,43 @@


#' Get Species
#'
#' Returns a complete list of all species information of species represented in the NPN
#' database.
#' Returns a complete list of all species information of species represented in
#' the NPN database.
#' @export
#' @template curl
#' @return A data frame with information on species in the NPN database and their IDs.
#' @param ... Currently unused.
#' @return A tibble with information on species in the NPN database and their
#' IDs.
#' @examples \dontrun{
#' npn_species()
#' npn_species_id(ids = 3)
#' }
npn_species <- function(...) {
tibble::as_tibble(
npn_GET(paste0(base(), 'species/getSpecies.json'), list(), TRUE, ...)
)
req <- base_req %>%
httr2::req_url_path_append('species/getSpecies.json')
resp <- httr2::req_perform(req)
out <- httr2::resp_body_json(resp, simplifyVector = TRUE)
#return:
tibble::as_tibble(out)
}

#' Get Species By ID
#'
#' Returns information about a species based on the NPN's unique ID for that species
#' Returns information about a species based on the NPN's unique ID for that
#' species
#' @export
#' @rdname npn_species
#' @param ids List of species ids for which to retrieve information
#' @return A data frame with information on species in the NPN database and their IDs, filtered by the species ID parameter.
#' @param ... Currently unused.
#' @return A tibble with information on species in the NPN database and their
#' IDs, filtered by the species ID parameter.
npn_species_id <- function(ids, ...) {

tt <- lapply(ids, function(z){
npn_GET(paste0(base(), 'species/getSpeciesById.json'), list(species_id = z), ...)
})
ldfply(tt)
req <- base_req %>%
httr2::req_url_path_append('species/getSpeciesById.json')
reqs <- lapply(ids, function(z) httr2::req_url_query(req, species_id = z))
resps <- httr2::req_perform_sequential(reqs)
out <- lapply(resps, function(x) httr2::resp_body_json(x, simplifyVector = TRUE) %>% tibble::as_tibble())

#return
dplyr::bind_rows(out)
}


Expand All @@ -40,74 +48,111 @@ npn_species_id <- function(ids, ...) {
#' @export
#' @rdname npn_species
#' @param state A US postal state code to filter results.
#' @param kingdom Filters results by taxonomic kingdom. Takes either 'Animalia' or 'Plantae'.
#' @return A data frame with information on species in the NPN database whose distribution includes a given state.
#' @param kingdom Filters results by taxonomic kingdom. Valid values include
#' `'Animalia'`, `'Plantae'`.
#' @param ... Currently unused.
#' @return A tibble with information on species in the NPN database whose
#' distribution includes a given state.
#' @examples \dontrun{
#' npn_species_state(state = "AZ")
#' npn_species_state(state = "AZ", kingdom = "Plantae")
#' }
npn_species_state <- function(state, kingdom = NULL, ...) {
args <- npnc(list(state = state, kingdom = kingdom))
ldfply(npn_GET(paste0(base(), 'species/getSpeciesByState.json'), args, ...))
# The API does accept multiple states in the form `?state[1]=CA&state[2]=AZ`.
# However, it isn't clear which results belong to which state, so for now this only accepts a single state.
# Entries other than US states appear to be valid, otherwise we could check for valid input with:
# state <- rlang::arg_match(state, datasets::state.abb)
# TODO:
# set kingdom default to something other than NULL
# kingdom <- rlang::arg_match0(kingdom, values = c("Plantae", "Animalia"))
req <- base_req %>%
httr2::req_url_path_append('species/getSpeciesByState.json') %>%
httr2::req_url_query(state = state, kingdom = kingdom)

resp <- httr2::req_perform(req)
out <- httr2::resp_body_json(resp, simplifyVector = TRUE)
#return:
tibble::as_tibble(out)
}



#' Species Search
#'
#' Search NPN species information using a number of different parameters, which can be used in conjunction with one another, including:
#' Search NPN species information using a number of different parameters, which
#' can be used in conjunction with one another, including:
#' - Species on which a particular group or groups are actually collecting data
#' - What species were observed in a given date range
#' - What species were observed at a particular station or stations
#' @param network filter species based on a list of unique identifiers of NPN groups that are actually observing data on the species. Takes a list of IDs
#' @param start_date filter species by date observed. This sets the start date of the date range and must be used in conjunction with end_date
#' @param end_date filter species by date observed. This sets the end date of the date range and must be used in conjunction with start_date
#' @param station_id filter species by a list of unique site identifiers
#' @return A data frame with information on species in the NPN database filtered by partner group, dates and station/site IDs.
#' @param network filter species based on identifiers of NPN groups that are
#' actually observing data on the species. Takes a single numeric ID.
#' @param start_date filter species by date observed. This sets the start date
#' of the date range and must be used in conjunction with `end_date`.
#' @param end_date filter species by date observed. This sets the end date of
#' the date range and must be used in conjunction with `start_date`.
#' @param station_id filter species by a numeric vector of unique site
#' identifiers.
#' @param ... Currently unused.
#' @return A tibble with information on species in the NPN database filtered by
#' partner group, dates and station/site IDs.
#' @export
#' @rdname npn_species
npn_species_search <- function(network=NULL, start_date=NULL, end_date=NULL, station_id=NULL, ...) {
args <- npnc(list(network_id = network, start_date = start_date,end_date = end_date))

for (i in seq_along(station_id)) {
args[paste0('station_ids[',i,']')] <- station_id[i]
}

ldfply(npn_GET(paste0(base(), 'species/getSpeciesFilter.json'), args, ...))
npn_species_search <- function(network = NULL,
start_date = NULL,
end_date = NULL,
station_id = NULL,
...) {
#TODO: multiple network IDs may be allowed in the API, but for now this function only takes a single network
req <- base_req %>%
httr2::req_url_path_append('species/getSpeciesFilter.json') %>%
httr2::req_url_query(
network = network,
start_date = start_date,
end_date = end_date,
!!!explode_query("station_id", station_id)
)
resp <- httr2::req_perform(req)
out <- httr2::resp_body_json(resp, simplifyVector = TRUE)
#return:
tibble::as_tibble(out)
}

#' Get Species Types
#'
#' Return all plant or animal functional types used in the NPN database.
#'
#' @param kingdom The kingdom for which to return functional types; either 'Animalia' or 'Plantae'. Defaults to Plantae.
#' @template curl
#' @return A data frame with a list of the functional types used in the NPN database, filtered by the specified kingdom.
#' @param kingdom Filters results by taxonomic kingdom. Valid values include
#' `'Animalia'`, `'Plantae'`, or `NULL` (which returns results
#' for both). Defaults to `'Plantae'`.
#' @param ... Currently unused.
#' @return A data frame with a list of the functional types used in the NPN
#' database, filtered by the specified kingdom.
#' @export
npn_species_types <- function(kingdom="Plantae", ...) {
end_point = NULL

if(kingdom == "Plantae"){
end_point = 'species/getPlantTypes.json'

}else if(kingdom == "Animalia"){
end_point = 'species/getAnimalTypes.json'
npn_species_types <- function(kingdom = "Plantae", ...) {
# if (!is.null(kingdom)) {
# kingdom <- rlang::arg_match0(kingdom, values = c("Plantae", "Animalia"))
# }
req_plant <- base_req %>%
httr2::req_url_path_append('species/getPlantTypes.json')
req_animal <- base_req %>%
httr2::req_url_path_append('species/getAnimalTypes.json')

resp <- NULL
if (kingdom == "Plantae") {
resp <- httr2::req_perform(req_plant)
} else if (kingdom == "Animalia") {
resp <- httr2::req_perform(req_animal)
}

if(!is.null(end_point)){
tibble::as_tibble(
npn_GET(paste0(base(), end_point), list(), TRUE, ...)
)
}else{
plant_types <- tibble::as_tibble(
npn_GET(paste0(base(), 'species/getPlantTypes.json'), list(), TRUE, ...)
)

animal_types <- tibble::as_tibble(
npn_GET(paste0(base(), 'species/getAnimalTypes.json'), list(), TRUE, ...)
)

rbindlist(list(plant_types, animal_types))
if (!is.null(resp)) {
out <- httr2::resp_body_json(resp, simplifyVector = TRUE)
return(tibble::as_tibble(out))
} else {
resps <- httr2::req_perform_sequential(list(req_plant, req_animal))
out <-
lapply(resps, function(x) httr2::resp_body_json(x, simplifyVector = TRUE)) %>%
dplyr::bind_rows()
#TODO add a column for `kingdom`?
return(tibble::as_tibble(out))
}

}
38 changes: 19 additions & 19 deletions R/npn_partner_groups.R
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@



#' Get Partner Groups
#'
#' Returns a list of all groups participating in the NPN's data collection program. These details can be used to further filter
#' other service endpoints' results.
#' Returns a list of all groups participating in the NPN's data collection
#' program. These details can be used to further filter other service endpoints'
#' results.
#'
#' @param use_hierarchy Boolean indicating whether or not the list of networks should be represented in a hierarchy. Defaults to FALSE.
#' @template curl
#' @return A data frame of partner groups, including ID and name.
#' @param use_hierarchy Boolean indicating whether or not the list of networks
#' should be represented in a hierarchy. Defaults to FALSE.
#' @param ... Currently unused.
#' @return A tibble of partner groups, including ID and name.
#' @export
npn_groups <- function(use_hierarchy=FALSE, ...) {
end_point <- NULL

if(use_hierarchy){
end_point <- 'networks/getNetworkTree.json'
}else{
end_point <- 'networks/getPartnerNetworks.json'
npn_groups <- function(use_hierarchy = FALSE, ...) {
if (isTRUE(use_hierarchy)) {
req <- base_req %>%
httr2::req_url_path_append('networks/getNetworkTree.json')
} else {
req <- base_req %>%
httr2::req_url_path_append('networks/getPartnerNetworks.json')
}

tibble::as_tibble(
npn_GET(paste0(base(), end_point), list(), TRUE, ...)
)

resp <- httr2::req_perform(req)
out <- httr2::resp_body_json(resp, simplifyVector = TRUE)
#return:
tibble::as_tibble(out)
#TODO output contains list column that cannot be easily unnested.
}
Loading
Loading