From 869651f95f5b3934480ead88d4658ff8eddff9c9 Mon Sep 17 00:00:00 2001 From: Jeremy Weiss Date: Thu, 27 Jun 2024 17:44:02 -0700 Subject: [PATCH 1/9] initial function setup --- R/az_15min.R | 4 +- R/az_daily.R | 82 +++++++++++++++---------- R/az_heat.R | 6 +- R/az_hourly.R | 6 +- R/az_lw15min.R | 4 +- R/az_lwdaily.R | 148 ++++++++++++++++++++++++++++++++++++++++++++++ R/parse_params.R | 37 +++++++++--- R/retrieve_data.R | 8 +-- 8 files changed, 243 insertions(+), 52 deletions(-) create mode 100644 R/az_lwdaily.R diff --git a/R/az_15min.R b/R/az_15min.R index 8a96cb4..ed83aba 100755 --- a/R/az_15min.R +++ b/R/az_15min.R @@ -26,7 +26,7 @@ #' the AZMet API. #' @return a tibble. For units and other metadata, see #' -#' @seealso [az_daily()], [az_heat()], [az_hourly()], [az_lw15min()] +#' @seealso [az_daily()], [az_heat()], [az_hourly()], [az_lw15min()], [az_lwdaily()] #' @source #' @importFrom rlang .data #' @export @@ -110,7 +110,7 @@ az_15min <- function(station_id = NULL, start_date_time = NULL, end_date_time = } if (nrow(out) == 0) { - warning("No data retrieved from API.") + warning("No data retrieved from API") # Return 0x0 tibble return(tibble::tibble()) } diff --git a/R/az_daily.R b/R/az_daily.R index 7bb2232..6af10ba 100644 --- a/R/az_daily.R +++ b/R/az_daily.R @@ -4,18 +4,21 @@ #' of weather stations and their locations see [station_info]. #' #' @param station_id station ID can be supplied as numeric vector (e.g. -#' `station_id = c(8, 37)`) or as character vector with the prefix "az" and 2 -#' digits (e.g. `station_id = c("az08", "az37")`) If left blank data for all -#' stations will be returned +#' `station_id = c(8, 37)`) or as character vector with the prefix "az" and +#' two digits (e.g. `station_id = c("az08", "az37")`). If left blank, data for all +#' stations will be returned. #' @param start_date A length-1 vector of class Date, POSIXct, or character in -#' YYYY-MM-DD format. Will be rounded **down** to the nearest day if more -#' precision is supplied. +#' YYYY-MM-DD format. Will be rounded **down** to the nearest day if more +#' precision is supplied. Defaults to the day before the current date (i.e., +#' the most recent complete day) if left blank. #' @param end_date A length-1 vector of class Date, POSIXct, or character in -#' YYYY-MM-DD format. Will be rounded **down** to the nearest day if more -#' precision is supplied. Defaults to the current date if left blank. +#' YYYY-MM-DD format. Will be rounded **down** to the nearest day if more +#' precision is supplied. Defaults to the day before the current date (i.e., +#' the most recent complete day) if left blank. #' @details If neither `start_date` nor `end_date` are supplied, the most recent -#' day of data will be returned. If only `start_date` is supplied, then the -#' end date defaults to the current date. Supplying only `end_date` will +#' day of data will be returned. If only `start_date` is supplied, then the +#' end date defaults to the day before the current date (i.e., +#' the most recent complete day). Supplying only `end_date` will #' result in an error. #' @note If `station_id` is supplied as a vector, multiple successive calls to #' the API will be made. You may find better performance getting data for all @@ -24,7 +27,7 @@ #' may take considerable time. #' @return a tibble. For units and other metadata, see #' -#' @seealso [az_15min()], [az_heat()], [az_hourly()], [az_lw15min()] +#' @seealso [az_15min()], [az_heat()], [az_hourly()], [az_lw15min()], [az_lwdaily()] #' @source #' #' @importFrom rlang .data @@ -43,18 +46,31 @@ #' az_daily(start_date = "2022-09-25") #' az_daily(start_date = "2022-09-25", end_date = "2022-09-26") #' } -#' + + az_daily <- function(station_id = NULL, start_date = NULL, end_date = NULL) { - #TODO: check for valid station IDs + # TODO: check for valid station IDs check_internet() + if(!is.null(end_date) & is.null(start_date)) { stop("If you supply `end_date`, you must also supply `start_date`") } + params <- - parse_params(station_id = station_id, start = start_date, end = end_date) + parse_params( + station_id = station_id, + start = start_date, + end = end_date, + hour = FALSE, + real_time = FALSE + ) + + tz = "America/Phoenix" + + + # Query API ----------------------------------------------------------------- - # Query API -------------------------------------------- if (is.null(start_date) & is.null(end_date)) { message("Querying data from ", params$start) } else { @@ -63,42 +79,48 @@ az_daily <- function(station_id = NULL, start_date = NULL, end_date = NULL) { if (length(station_id) <= 1) { out <- - retrieve_data(params$station_id, - params$start_f, - params$time_interval, - endpoint = "daily") + retrieve_data( + params$station_id, + params$start_f, + params$time_interval, + endpoint = "daily" + ) } else if (length(station_id) > 1) { out <- purrr::map_df( params$station_id, function(x) { - retrieve_data(x, - params$start_f, - params$time_interval, - endpoint = "daily") + retrieve_data( + x, + params$start_f, + params$time_interval, + endpoint = "daily" + ) } ) } if (nrow(out) == 0) { warning("No data retrieved from API") - #return 0x0 tibble for type consistency + # Return 0x0 tibble for type consistency return(tibble::tibble()) } - #Check if any data is missing + # Check if any data are missing n_obs <- out %>% dplyr::summarise(n = dplyr::n(), .by = dplyr::all_of("meta_station_id")) %>% dplyr::filter(.data$n < as.numeric(lubridate::period(params$time_interval), "day") + 1) if (nrow(n_obs) != 0 | # Also warn if the missing data is just at the end - lubridate::ymd(max(out$datetime), tz = "America/Phoenix") < params$end) { - warning("Some requested data were unavailable") + lubridate::ymd(max(out$datetime), tz = tz) < params$end) { + warning("Some requested data were unavailable.") } - # Wrangle output ---------------------------------------------------------- + + # Wrangle output ------------------------------------------------------------- + out <- out %>% - #move metadata to beginning + # Move metadata to beginning dplyr::select(dplyr::starts_with("meta_"), dplyr::everything()) %>% dplyr::mutate(dplyr::across( c(-"meta_station_id", -"meta_station_name", -"datetime", -"wind_2min_timestamp"), @@ -106,7 +128,7 @@ az_daily <- function(station_id = NULL, start_date = NULL, end_date = NULL) { )) %>% dplyr::filter(.data$meta_station_id != "az99") %>% dplyr::mutate(datetime = lubridate::ymd(.data$datetime)) %>% - #convert NAs + # Convert NAs dplyr::mutate( dplyr::across( tidyselect::where(is.numeric), @@ -124,7 +146,7 @@ az_daily <- function(station_id = NULL, start_date = NULL, end_date = NULL) { dplyr::mutate( wind_2min_timestamp = lubridate::with_tz( lubridate::parse_date_time(.data$wind_2min_timestamp, orders = "ymdHMSz"), - tzone = "America/Phoenix" + tzone = tz ) ) diff --git a/R/az_heat.R b/R/az_heat.R index a6b1194..4d695d2 100644 --- a/R/az_heat.R +++ b/R/az_heat.R @@ -26,7 +26,7 @@ #' dataframe. #' @return a tibble. For units and other metadata, see #' -#' @seealso [az_15min()], [az_daily()], [az_hourly()], [az_lw15min()] +#' @seealso [az_15min()], [az_daily()], [az_hourly()], [az_lw15min()], [az_lwdaily()] #' @source #' @importFrom rlang .data #' @export @@ -52,8 +52,8 @@ #' az_heat <- function(station_id = NULL, start_date = NULL, end_date = NULL) { tz <- "America/Phoenix" - #TODO: document output columns or link to API docs if appropriate - #TODO: check for valid station IDs + # TODO: document output columns or link to API docs if appropriate + # TODO: check for valid station IDs check_internet() # If no start date supplied, default is Jan 1 of current year. if (is.null(start_date)) { diff --git a/R/az_hourly.R b/R/az_hourly.R index e81e40c..475d7f8 100644 --- a/R/az_hourly.R +++ b/R/az_hourly.R @@ -5,7 +5,7 @@ #' #' @param station_id station ID can be supplied as numeric vector (e.g. #' `station_id = c(8, 37)`) or as character vector with the prefix "az" and 2 -#' digits (e.g. `station_id = c("az08", "az37")`) If left blank data for all +#' digits (e.g. `station_id = c("az08", "az37")`) If left blank, data for all #' stations will be returned #' @param start_date_time A length-1 vector of class POSIXct or character in #' YYYY-MM-DD HH format, in AZ time. Will be rounded **down** to the nearest @@ -28,7 +28,7 @@ #' take considerable time. #' @return a tibble. For units and other metadata, see #' -#' @seealso [az_15min()], [az_daily()], [az_heat()], [az_lw15min()] +#' @seealso [az_15min()], [az_daily()], [az_heat()], [az_lw15min()], [az_lwdaily()] #' @source #' @importFrom rlang .data #' @export @@ -49,7 +49,7 @@ #' az_hourly <- function(station_id = NULL, start_date_time = NULL, end_date_time = NULL) { - #TODO: check for valid station IDs + # TODO: check for valid station IDs check_internet() if(!is.null(end_date_time) & is.null(start_date_time)) { stop("If you supply `end_date_time`, you must also supply `start_date_time`") diff --git a/R/az_lw15min.R b/R/az_lw15min.R index de0e750..b677251 100644 --- a/R/az_lw15min.R +++ b/R/az_lw15min.R @@ -27,7 +27,7 @@ #' the AZMet API. #' @return a tibble. For units and other metadata, see #' -#' @seealso [az_15min()], [az_daily()], [az_heat()], [az_hourly()] +#' @seealso [az_15min()], [az_daily()], [az_heat()], [az_hourly()], [az_lwdaily()] #' @source #' @importFrom rlang .data #' @export @@ -111,7 +111,7 @@ az_lw15min <- function(station_id = NULL, start_date_time = NULL, end_date_time } if (nrow(out) == 0) { - warning("No data retrieved from API.") + warning("No data retrieved from API") # Return 0x0 tibble return(tibble::tibble()) } diff --git a/R/az_lwdaily.R b/R/az_lwdaily.R new file mode 100644 index 0000000..e34c220 --- /dev/null +++ b/R/az_lwdaily.R @@ -0,0 +1,148 @@ +#' Retrieve Daily Leaf Wetness Data from AZMET +#' +#' Retrieves daily leaf wetness data from the Arizona Meteorological Network +#' API. Currently, these data only are available from stations in the Yuma area. +#' For a list of stations and their locations see [station_info]. +#' +#' @param station_id station ID can be supplied as numeric vector (e.g. +#' `station_id = c(8, 37)`) or as character vector with the prefix "az" and +#' two digits (e.g. `station_id = c("az08", "az37")`). If left blank, data for +#' all stations will be returned. +#' @param start_date A length-1 vector of class Date, POSIXct, or character in +#' YYYY-MM-DD format. Will be rounded **down** to the nearest day if more +#' precision is supplied. Defaults to the day before the current date (i.e., +#' the most recent complete day) if left blank. +#' @param end_date A length-1 vector of class Date, POSIXct, or character in +#' YYYY-MM-DD format. Will be rounded **down** to the nearest day if more +#' precision is supplied. Defaults to the day before the current date (i.e., +#' the most recent complete day) if left blank. +#' @details If neither `start_date` nor `end_date` are supplied, the most recent +#' day of data will be returned. If only `start_date` is supplied, then the +#' end date defaults to the day before the current date (i.e., +#' the most recent complete day). Supplying only `end_date` will +#' result in an error. +#' @note If `station_id` is supplied as a vector, multiple successive calls to +#' the API will be made. You may find better performance getting data for all +#' the stations by leaving `station_id` blank and subsetting the resulting +#' dataframe. Requests for data from all stations for more than 6-12 months +#' may take considerable time. +#' @return a tibble. For units and other metadata, see +#' +#' @seealso [az_15min()], [az_daily()], [az_hourly()], [az_heat()], [az_lw15min()] +#' @source +#' +#' @importFrom rlang .data +#' @export +#' +#' @examples +#' \dontrun{ +#' # Most recent data for all stations: +#' az_lwdaily() +#' +#' # Specify stations: +#' az_lwdaily(station_id = c(1, 2)) +#' az_lwdaily(station_id = c("az01", "az02")) +#' +#' # Specify dates: +#' az_lwdaily(start_date = "2022-09-25") +#' az_lwdaily(start_date = "2022-09-25", end_date = "2022-09-26") +#' } + + +az_lwdaily <- function(station_id = NULL, start_date = NULL, end_date = NULL) { + + # TODO: check for valid station IDs + check_internet() + + if(!is.null(end_date) & is.null(start_date)) { + stop("If you supply `end_date`, you must also supply `start_date`") + } + + params <- + parse_params( + station_id = station_id, + start = start_date, + end = end_date, + hour = FALSE, + lwdaily = TRUE, + real_time = FALSE + ) + + + # Query API ----------------------------------------------------------------- + + if (is.null(start_date) & is.null(end_date)) { + message("Querying data from ", params$start) + } else { + message("Querying data from ", params$start, " through ", params$end) + } + + if (length(station_id) <= 1) { + out <- + retrieve_data( + params$station_id, + params$start_f, + params$time_interval, + endpoint = "lwdaily" + ) + } else if (length(station_id) > 1) { + out <- + purrr::map_df( + params$station_id, + function(x) { + retrieve_data( + x, + params$start_f, + params$time_interval, + endpoint = "lwdaily" + ) + } + ) + } + + if (nrow(out) == 0) { + warning("No data retrieved from API") + # Return 0x0 tibble for type consistency + return(tibble::tibble()) + } + + # Check if any data are missing + n_obs <- out %>% + dplyr::summarise(n = dplyr::n(), .by = dplyr::all_of("meta_station_id")) %>% + dplyr::filter(.data$n < as.numeric(lubridate::period(params$time_interval), "day") + 1) + if (nrow(n_obs) != 0) {#| + # Also warn if the missing data is just at the end + #lubridate::ymd(max(out$datetime), tz = tz) < params$end) { + #lubridate::as_date(max(out$datetime)) < params$end) { + warning("Some requested data were unavailable.") + } + + + # Wrangle output ------------------------------------------------------------- + + out <- out %>% + # Move metadata to beginning + dplyr::select(dplyr::starts_with("meta_"), dplyr::everything()) %>% + dplyr::mutate(dplyr::across( + c(-"meta_station_id", -"meta_station_name", -"datetime"), + as.numeric + )) %>% + dplyr::filter(.data$meta_station_id != "az99") %>% + #dplyr::mutate(datetime = lubridate::ymd(.data$datetime)) %>% + dplyr::mutate(datetime = lubridate::as_date(.data$datetime)) %>% + # Convert NAs + dplyr::mutate( + dplyr::across( + tidyselect::where(is.numeric), + function(x) + dplyr::if_else(x %in% c(-999, -9999, -99999, -7999, 999, 999.9, 9999), NA_real_, x) + ) + ) + + if (length(unique(out$datetime)) == 1) { + message("Returning data from ", unique(out$datetime)) + } else { + message("Returning data from ", min(out$datetime), " through ", max(out$datetime)) + } + return(out) +} diff --git a/R/parse_params.R b/R/parse_params.R index a987fff..ded78f8 100644 --- a/R/parse_params.R +++ b/R/parse_params.R @@ -4,6 +4,7 @@ #' @param start start date or date time #' @param end end date or date time #' @param hour logical; do `start` and `end` contain hours? +#' @param lwdaily logical; is request for daily leaf wetness data? #' @param real_time logical; is request for real-time data? #' #' @note If `hour = TRUE`, `start` and `end` can be character or POSIXct and @@ -17,7 +18,7 @@ #' @noRd -parse_params <- function(station_id, start, end, hour = FALSE, real_time = FALSE) { +parse_params <- function(station_id, start, end, hour = FALSE, lwdaily = FALSE, real_time = FALSE) { is_ymd <- function(x) { !is.na(lubridate::ymd(x, quiet = TRUE)) @@ -59,18 +60,24 @@ parse_params <- function(station_id, start, end, hour = FALSE, real_time = FALSE # start_f/time_interval: what is actually passed to the API ######################################### + if (is.null(end)) { if (isTRUE(hour)) { # Hourly data end_ <- format( # Keep as character until later, for consistency lubridate::floor_date(lubridate::now(tzone = tz), "hour"), "%Y-%m-%d %H:%M:%S" ) - } else if (isTRUE(real_time)) { # 15min data + } else if (isTRUE(real_time)) { # 15min data, both weather and leaf wetness end_ <- format( # Keep as character until later, for consistency lubridate::now(tzone = tz), "%Y-%m-%d %H:%M:%S" ) - } else { # Daily data + } else if (isTRUE(lwdaily)) { # Daily leaf wetness data + end_ <- paste( # Keep as character until later, for consistency + lubridate::today(tzone = tz) - lubridate::days(1), + "23:59:59" + ) + } else { # Daily weather and leaf wetness data end_ <- format( # Keep as character until later, for consistency lubridate::today(tzone = tz) - lubridate::days(1), "%Y-%m-%d %H:%M:%S" @@ -85,7 +92,9 @@ parse_params <- function(station_id, start, end, hour = FALSE, real_time = FALSE end_ <- paste(end, "23:59:59") } else if (isTRUE(real_time) & is_ymd(end)) { # 15min data end_ <- paste(end, format(lubridate::now(tzone = tz), "%H:%M:%S")) - } else { # Daily data + } else if (isTRUE(lwdaily)) { # Daily leaf wetness data + end_ <- paste(end, "23:59:59") + } else { # Daily weather data end_ <- end } } @@ -101,7 +110,12 @@ parse_params <- function(station_id, start, end, hour = FALSE, real_time = FALSE lubridate::now(tzone = tz) - lubridate::minutes(15), "%Y-%m-%d %H:%M:%S" ) - } else { # Daily data + } else if (isTRUE(lwdaily)) { # Daily leaf wetness data + start_ <- paste( # Keep as character until later, for consistency + lubridate::today(tzone = tz) - lubridate::days(1), + "23:00:00" + ) + } else { # Daily weather data start_ <- format( # Keep as character until later, for consistency lubridate::today(tzone = tz) - lubridate::days(1), "%Y-%m-%d" @@ -112,7 +126,9 @@ parse_params <- function(station_id, start, end, hour = FALSE, real_time = FALSE start_ <- paste(start, "01:00:00") } else if (isTRUE(real_time) & is_ymd(start)) { # 15min data start_ <- paste(start, "00:00:01") - } else { # Daily data + } else if (isTRUE(lwdaily)) { # Daily leaf wetness data + start_ <- paste(start, "23:00:00") + } else { # Daily weather and leaf wetness data start_ <- start } } @@ -135,7 +151,12 @@ parse_params <- function(station_id, start, end, hour = FALSE, real_time = FALSE lubridate::parse_date_time(x, orders = c("YmdHMS", "YmdHM", "YmdH", "Ymd"), tz = tz) %>% lubridate::floor_date(unit = "secs") } - } else { # Daily data + } else if (isTRUE(lwdaily)) { # Daily leaf wetness data + parse_fun <- function(x, end = FALSE) { + lubridate::parse_date_time(x, orders = c("YmdHMS", "YmdHM", "YmdH", "Ymd"), tz = tz) %>% + lubridate::floor_date(unit = "min") + } + } else { # Daily weather data parse_fun <- function(x, end = FALSE) { lubridate::parse_date_time(x, orders = c("Ymd", "YmdHMS", "YmdHM", "YmdH"), tz = tz) %>% lubridate::floor_date(unit = "day") %>% @@ -193,7 +214,7 @@ parse_params <- function(station_id, start, end, hour = FALSE, real_time = FALSE if (end_parsed < start_parsed) { stop("`end_date_time` is before `start_date_time`!") } - } else { # Daily data + } else { # Daily weather and leaf wetness data if (!is.null(start) & start_parsed >= lubridate::today(tzone = tz)) { stop("Please supply a `start_date` earlier than today.") } diff --git a/R/retrieve_data.R b/R/retrieve_data.R index 1477f6e..f9d584f 100644 --- a/R/retrieve_data.R +++ b/R/retrieve_data.R @@ -15,7 +15,7 @@ retrieve_data <- station_id, start_f, time_interval, - endpoint = c("15min", "daily", "hourly", "hueto", "lw15min"), + endpoint = c("15min", "daily", "hourly", "hueto", "lw15min", "lwdaily"), print_call = getOption("azmet.print_api_call") ) { @@ -43,9 +43,9 @@ retrieve_data <- data_tidy <- data_raw$data %>% purrr::compact() %>% - purrr::map(purrr::compact) %>% #removes any columns that are NULL (i.e. no data) + purrr::map(purrr::compact) %>% # Removes any columns that are NULL (i.e. no data) purrr::map(tibble::as_tibble) %>% - purrr::list_rbind() # missing columns for individual sites will be all NAs + purrr::list_rbind() # Missing columns for individual sites will be all NAs attributes(data_tidy) <- append( @@ -54,5 +54,5 @@ retrieve_data <- ) data_tidy - #TODO: Check for 0x0 tibble and error + # TODO: Check for 0x0 tibble and error } From 224eebd09dd2a417946f8bde45de394ad0eeddfd Mon Sep 17 00:00:00 2001 From: Jeremy Weiss Date: Fri, 28 Jun 2024 17:16:38 -0700 Subject: [PATCH 2/9] troubleshooting `start_date` error --- R/az_15min.R | 3 ++- R/az_daily.R | 7 ++++--- R/az_heat.R | 9 +++++---- R/az_hourly.R | 7 ++++--- R/az_lw15min.R | 5 +++-- R/az_lwdaily.R | 38 ++++++++++++++++++-------------------- R/parse_params.R | 26 +++----------------------- 7 files changed, 39 insertions(+), 56 deletions(-) diff --git a/R/az_15min.R b/R/az_15min.R index ed83aba..2e977f0 100755 --- a/R/az_15min.R +++ b/R/az_15min.R @@ -1,7 +1,8 @@ #' Retrieve 15-minute Weather Data from AZMet #' #' Retrieves 15-minute data from the AZMet (Arizona Meteorological Network) API. -#' For a list of weather stations and their locations see [station_info]. +#' For a list of weather stations and their locations see [station_info], or +#' visit https://azmet.arizona.edu/about. #' #' @param station_id Station ID can be supplied as numeric vector (e.g. #' `station_id = c(8, 37)`) or as character vector with the prefix "az" and diff --git a/R/az_daily.R b/R/az_daily.R index 6af10ba..3e115d4 100644 --- a/R/az_daily.R +++ b/R/az_daily.R @@ -1,7 +1,8 @@ #' Retrieve Daily Weather Data from AZMET #' #' Retrieves daily data from the Arizona Meteorological Network API. For a list -#' of weather stations and their locations see [station_info]. +#' of weather stations and their locations see [station_info], or visit +#' https://azmet.arizona.edu/about. #' #' @param station_id station ID can be supplied as numeric vector (e.g. #' `station_id = c(8, 37)`) or as character vector with the prefix "az" and @@ -26,9 +27,9 @@ #' dataframe. Requests for data from all stations for more than 6-12 months #' may take considerable time. #' @return a tibble. For units and other metadata, see -#' +#' #' @seealso [az_15min()], [az_heat()], [az_hourly()], [az_lw15min()], [az_lwdaily()] -#' @source +#' @source #' #' @importFrom rlang .data #' @export diff --git a/R/az_heat.R b/R/az_heat.R index 4d695d2..6edc152 100644 --- a/R/az_heat.R +++ b/R/az_heat.R @@ -1,9 +1,10 @@ #' Retrieve Accumulated Heat Units and Evapotranspiration #' #' Retrieves accumulated heat units and reference evapotranspiration units from -#' the Arizona Meteorological Network API. By default, returned values are +#' the Arizona Meteorological Network API. By default, returned values are #' cumulative since January 1 of the current year. For a list of weather -#' stations and their locations see [station_info]. +#' stations and their locations see [station_info], or visit +#' https://azmet.arizona.edu/about. #' #' @param station_id station ID can be supplied as numeric vector (e.g. #' `station_id = c(8, 37)`) or as character vector with the prefix "az" and 2 @@ -25,9 +26,9 @@ #' the stations by leaving `station_id` blank and subsetting the resulting #' dataframe. #' @return a tibble. For units and other metadata, see -#' +#' #' @seealso [az_15min()], [az_daily()], [az_hourly()], [az_lw15min()], [az_lwdaily()] -#' @source +#' @source #' @importFrom rlang .data #' @export #' diff --git a/R/az_hourly.R b/R/az_hourly.R index 475d7f8..4c5e9af 100644 --- a/R/az_hourly.R +++ b/R/az_hourly.R @@ -1,7 +1,8 @@ #' Retrieve Hourly Weather Data #' #' Retrieves hourly weather data from the Arizona Meteorological Network API. -#' For a list of weather stations and their locations see [station_info]. +#' For a list of weather stations and their locations see [station_info], or +#' visit https://azmet.arizona.edu/about. #' #' @param station_id station ID can be supplied as numeric vector (e.g. #' `station_id = c(8, 37)`) or as character vector with the prefix "az" and 2 @@ -27,9 +28,9 @@ #' dataframe. Requests for data from all stations for more than 10-15 days may #' take considerable time. #' @return a tibble. For units and other metadata, see -#' +#' #' @seealso [az_15min()], [az_daily()], [az_heat()], [az_lw15min()], [az_lwdaily()] -#' @source +#' @source #' @importFrom rlang .data #' @export #' diff --git a/R/az_lw15min.R b/R/az_lw15min.R index b677251..a95ab1a 100644 --- a/R/az_lw15min.R +++ b/R/az_lw15min.R @@ -1,8 +1,9 @@ #' Retrieve 15-minute Leaf Wetness Data from AZMet #' #' Retrieves 15-minute leaf-wetness data from the AZMet (Arizona Meteorological -#' Network) API. Currently, these data only are available from stations in the -#' Yuma area. For a list of stations and their locations see [station_info]. +#' Network) API. Currently, these data only are available from weather stations +#' in the Yuma area. For a list of stations and their locations see +#' [station_info], or visit https://azmet.arizona.edu/about. #' #' @param station_id Station ID can be supplied as numeric vector (e.g. #' `station_id = c(8, 37)`) or as character vector with the prefix "az" and diff --git a/R/az_lwdaily.R b/R/az_lwdaily.R index e34c220..18db25d 100644 --- a/R/az_lwdaily.R +++ b/R/az_lwdaily.R @@ -1,8 +1,9 @@ -#' Retrieve Daily Leaf Wetness Data from AZMET +#' Retrieve Daily Leaf Wetness Data from AZMet #' #' Retrieves daily leaf wetness data from the Arizona Meteorological Network -#' API. Currently, these data only are available from stations in the Yuma area. -#' For a list of stations and their locations see [station_info]. +#' API. Currently, these data only are available from weather stations in the +#' Yuma area. For a list of stations and their locations see [station_info], or +#' visit https://azmet.arizona.edu/about. #' #' @param station_id station ID can be supplied as numeric vector (e.g. #' `station_id = c(8, 37)`) or as character vector with the prefix "az" and @@ -18,18 +19,17 @@ #' the most recent complete day) if left blank. #' @details If neither `start_date` nor `end_date` are supplied, the most recent #' day of data will be returned. If only `start_date` is supplied, then the -#' end date defaults to the day before the current date (i.e., -#' the most recent complete day). Supplying only `end_date` will -#' result in an error. +#' end date defaults to the day before the current date (i.e., the most recent +#' complete day). Supplying only `end_date` will result in an error. #' @note If `station_id` is supplied as a vector, multiple successive calls to #' the API will be made. You may find better performance getting data for all #' the stations by leaving `station_id` blank and subsetting the resulting #' dataframe. Requests for data from all stations for more than 6-12 months #' may take considerable time. #' @return a tibble. For units and other metadata, see -#' +#' #' @seealso [az_15min()], [az_daily()], [az_hourly()], [az_heat()], [az_lw15min()] -#' @source +#' @source #' #' @importFrom rlang .data #' @export @@ -55,7 +55,7 @@ az_lwdaily <- function(station_id = NULL, start_date = NULL, end_date = NULL) { check_internet() if(!is.null(end_date) & is.null(start_date)) { - stop("If you supply `end_date`, you must also supply `start_date`") + stop("If you supply `end_date`, you must also supply `start_date`.") } params <- @@ -64,7 +64,6 @@ az_lwdaily <- function(station_id = NULL, start_date = NULL, end_date = NULL) { start = start_date, end = end_date, hour = FALSE, - lwdaily = TRUE, real_time = FALSE ) @@ -72,9 +71,9 @@ az_lwdaily <- function(station_id = NULL, start_date = NULL, end_date = NULL) { # Query API ----------------------------------------------------------------- if (is.null(start_date) & is.null(end_date)) { - message("Querying data from ", params$start) + message("Querying data from ", params$start, " ...") } else { - message("Querying data from ", params$start, " through ", params$end) + message("Querying data from ", params$start, " through ", params$end, " ...") } if (length(station_id) <= 1) { @@ -110,10 +109,9 @@ az_lwdaily <- function(station_id = NULL, start_date = NULL, end_date = NULL) { n_obs <- out %>% dplyr::summarise(n = dplyr::n(), .by = dplyr::all_of("meta_station_id")) %>% dplyr::filter(.data$n < as.numeric(lubridate::period(params$time_interval), "day") + 1) - if (nrow(n_obs) != 0) {#| + if (nrow(n_obs) != 0 | # Also warn if the missing data is just at the end - #lubridate::ymd(max(out$datetime), tz = tz) < params$end) { - #lubridate::as_date(max(out$datetime)) < params$end) { + lubridate::ymd(max(out$date)) < params$end) { warning("Some requested data were unavailable.") } @@ -124,12 +122,12 @@ az_lwdaily <- function(station_id = NULL, start_date = NULL, end_date = NULL) { # Move metadata to beginning dplyr::select(dplyr::starts_with("meta_"), dplyr::everything()) %>% dplyr::mutate(dplyr::across( - c(-"meta_station_id", -"meta_station_name", -"datetime"), + c(-"meta_station_id", -"meta_station_name", -"date", -"datetime"), as.numeric )) %>% dplyr::filter(.data$meta_station_id != "az99") %>% - #dplyr::mutate(datetime = lubridate::ymd(.data$datetime)) %>% - dplyr::mutate(datetime = lubridate::as_date(.data$datetime)) %>% + dplyr::mutate(date = lubridate::ymd(.data$date)) %>% + #######dplyr::mutate(datetime = lubridate::as_date(lubridate::ymd_hms(.data$datetime, tz = "America/Phoenix"))) %>% # Convert NAs dplyr::mutate( dplyr::across( @@ -140,9 +138,9 @@ az_lwdaily <- function(station_id = NULL, start_date = NULL, end_date = NULL) { ) if (length(unique(out$datetime)) == 1) { - message("Returning data from ", unique(out$datetime)) + message("Returning data from ", unique(out$date)) } else { - message("Returning data from ", min(out$datetime), " through ", max(out$datetime)) + message("Returning data from ", min(out$date), " through ", max(out$date)) } return(out) } diff --git a/R/parse_params.R b/R/parse_params.R index ded78f8..c57843e 100644 --- a/R/parse_params.R +++ b/R/parse_params.R @@ -4,21 +4,20 @@ #' @param start start date or date time #' @param end end date or date time #' @param hour logical; do `start` and `end` contain hours? -#' @param lwdaily logical; is request for daily leaf wetness data? #' @param real_time logical; is request for real-time data? #' #' @note If `hour = TRUE`, `start` and `end` can be character or POSIXct and -#' will be rounded **down** to the nearest hour. If character, then they must +#' will be rounded **down** to the nearest hour. If character, then they must #' at least contain the hour (e.g. "2022-01-12 13" for 1pm on Jan 12, 2022). #' If `hour = FALSE` then class Date is also accepted and values will be -#' rounded **down** to the nearest whole day. Dates and times should be in +#' rounded **down** to the nearest whole day. Dates and times should be in #' Arizona time. #' #' @return a list #' @noRd -parse_params <- function(station_id, start, end, hour = FALSE, lwdaily = FALSE, real_time = FALSE) { +parse_params <- function(station_id, start, end, hour = FALSE, real_time = FALSE) { is_ymd <- function(x) { !is.na(lubridate::ymd(x, quiet = TRUE)) @@ -72,11 +71,6 @@ parse_params <- function(station_id, start, end, hour = FALSE, lwdaily = FALSE, lubridate::now(tzone = tz), "%Y-%m-%d %H:%M:%S" ) - } else if (isTRUE(lwdaily)) { # Daily leaf wetness data - end_ <- paste( # Keep as character until later, for consistency - lubridate::today(tzone = tz) - lubridate::days(1), - "23:59:59" - ) } else { # Daily weather and leaf wetness data end_ <- format( # Keep as character until later, for consistency lubridate::today(tzone = tz) - lubridate::days(1), @@ -92,8 +86,6 @@ parse_params <- function(station_id, start, end, hour = FALSE, lwdaily = FALSE, end_ <- paste(end, "23:59:59") } else if (isTRUE(real_time) & is_ymd(end)) { # 15min data end_ <- paste(end, format(lubridate::now(tzone = tz), "%H:%M:%S")) - } else if (isTRUE(lwdaily)) { # Daily leaf wetness data - end_ <- paste(end, "23:59:59") } else { # Daily weather data end_ <- end } @@ -110,11 +102,6 @@ parse_params <- function(station_id, start, end, hour = FALSE, lwdaily = FALSE, lubridate::now(tzone = tz) - lubridate::minutes(15), "%Y-%m-%d %H:%M:%S" ) - } else if (isTRUE(lwdaily)) { # Daily leaf wetness data - start_ <- paste( # Keep as character until later, for consistency - lubridate::today(tzone = tz) - lubridate::days(1), - "23:00:00" - ) } else { # Daily weather data start_ <- format( # Keep as character until later, for consistency lubridate::today(tzone = tz) - lubridate::days(1), @@ -126,8 +113,6 @@ parse_params <- function(station_id, start, end, hour = FALSE, lwdaily = FALSE, start_ <- paste(start, "01:00:00") } else if (isTRUE(real_time) & is_ymd(start)) { # 15min data start_ <- paste(start, "00:00:01") - } else if (isTRUE(lwdaily)) { # Daily leaf wetness data - start_ <- paste(start, "23:00:00") } else { # Daily weather and leaf wetness data start_ <- start } @@ -151,11 +136,6 @@ parse_params <- function(station_id, start, end, hour = FALSE, lwdaily = FALSE, lubridate::parse_date_time(x, orders = c("YmdHMS", "YmdHM", "YmdH", "Ymd"), tz = tz) %>% lubridate::floor_date(unit = "secs") } - } else if (isTRUE(lwdaily)) { # Daily leaf wetness data - parse_fun <- function(x, end = FALSE) { - lubridate::parse_date_time(x, orders = c("YmdHMS", "YmdHM", "YmdH", "Ymd"), tz = tz) %>% - lubridate::floor_date(unit = "min") - } } else { # Daily weather data parse_fun <- function(x, end = FALSE) { lubridate::parse_date_time(x, orders = c("Ymd", "YmdHMS", "YmdHM", "YmdH"), tz = tz) %>% From 4dffff9559d22175412b68e144a2a1db32d2214a Mon Sep 17 00:00:00 2001 From: Jeremy Weiss Date: Mon, 1 Jul 2024 16:51:18 -0700 Subject: [PATCH 3/9] minor change, `date` v. `datetime` variables --- R/az_lwdaily.R | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/R/az_lwdaily.R b/R/az_lwdaily.R index 18db25d..eb39904 100644 --- a/R/az_lwdaily.R +++ b/R/az_lwdaily.R @@ -28,7 +28,7 @@ #' may take considerable time. #' @return a tibble. For units and other metadata, see #' -#' @seealso [az_15min()], [az_daily()], [az_hourly()], [az_heat()], [az_lw15min()] +#' @seealso [az_15min()], [az_daily()], [az_heat()], [az_hourly()], [az_lw15min()] #' @source #' #' @importFrom rlang .data @@ -137,7 +137,7 @@ az_lwdaily <- function(station_id = NULL, start_date = NULL, end_date = NULL) { ) ) - if (length(unique(out$datetime)) == 1) { + if (length(unique(out$date)) == 1) { message("Returning data from ", unique(out$date)) } else { message("Returning data from ", min(out$date), " through ", max(out$date)) From cd6537a59e9cc7ec417ae31f51ad7dbebf4db59e Mon Sep 17 00:00:00 2001 From: Jeremy Weiss Date: Wed, 3 Jul 2024 16:12:09 -0700 Subject: [PATCH 4/9] minor edits to warning text, start datetime of 15-minute data --- R/az_15min.R | 2 +- R/az_lw15min.R | 2 +- R/parse_params.R | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/R/az_15min.R b/R/az_15min.R index 2e977f0..3e07909 100755 --- a/R/az_15min.R +++ b/R/az_15min.R @@ -72,7 +72,7 @@ az_15min <- function(station_id = NULL, start_date_time = NULL, end_date_time = # Query API ------------------------------------------------------------------ if (is.null(start_date_time) & is.null(end_date_time)) { - message("Querying most recent date-time of 15-minute data ...") + message("Querying most recent datetime of 15-minute data ...") } else { message( "Querying data from ", format(params$start, "%Y-%m-%d %H:%M:%S")," through ", format(params$end, "%Y-%m-%d %H:%M:%S"), " ..." diff --git a/R/az_lw15min.R b/R/az_lw15min.R index a95ab1a..50f4d45 100644 --- a/R/az_lw15min.R +++ b/R/az_lw15min.R @@ -73,7 +73,7 @@ az_lw15min <- function(station_id = NULL, start_date_time = NULL, end_date_time # Query API ------------------------------------------------------------------ if (is.null(start_date_time) & is.null(end_date_time)) { - message("Querying most recent date-time of leaf wetness 15-minute data ...") + message("Querying most recent datetime of leaf wetness 15-minute data ...") } else { message( "Querying data from ", format(params$start, "%Y-%m-%d %H:%M:%S")," through ", format(params$end, "%Y-%m-%d %H:%M:%S"), " ..." diff --git a/R/parse_params.R b/R/parse_params.R index c57843e..ed5a2d2 100644 --- a/R/parse_params.R +++ b/R/parse_params.R @@ -81,7 +81,7 @@ parse_params <- function(station_id, start, end, hour = FALSE, real_time = FALSE # For hourly, if only ymd is supplied to `end`, round up to end of day. On a # given day, hourly data go from 1:00:00 to 23:59:59. For 15min, if only ymd # is supplied to `end`, set to current Arizona time. On a given day, 15 min - # data go from 00:00:01 to 23:59:59 + # data go from 00:00:00 to 23:59:59 if (isTRUE(hour) & is_ymd(end)) { # Hourly data end_ <- paste(end, "23:59:59") } else if (isTRUE(real_time) & is_ymd(end)) { # 15min data @@ -112,7 +112,7 @@ parse_params <- function(station_id, start, end, hour = FALSE, real_time = FALSE if (isTRUE(hour) & is_ymd(start)) { # Hourly data start_ <- paste(start, "01:00:00") } else if (isTRUE(real_time) & is_ymd(start)) { # 15min data - start_ <- paste(start, "00:00:01") + start_ <- paste(start, "00:00:00") } else { # Daily weather and leaf wetness data start_ <- start } From 7b72c40bc63058610147ca2ad11d7f4a689ded44 Mon Sep 17 00:00:00 2001 From: Jeremy Weiss Date: Mon, 8 Jul 2024 12:30:35 -0700 Subject: [PATCH 5/9] handle `datetime` format in `az_lwdaily()` --- R/az_lwdaily.R | 2 +- R/parse_params.R | 2 +- R/retrieve_data.R | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/R/az_lwdaily.R b/R/az_lwdaily.R index eb39904..bec33de 100644 --- a/R/az_lwdaily.R +++ b/R/az_lwdaily.R @@ -127,7 +127,7 @@ az_lwdaily <- function(station_id = NULL, start_date = NULL, end_date = NULL) { )) %>% dplyr::filter(.data$meta_station_id != "az99") %>% dplyr::mutate(date = lubridate::ymd(.data$date)) %>% - #######dplyr::mutate(datetime = lubridate::as_date(lubridate::ymd_hms(.data$datetime, tz = "America/Phoenix"))) %>% + dplyr::mutate(datetime = lubridate::ymd_hms(.data$datetime, tz = "America/Phoenix")) %>% # Convert NAs dplyr::mutate( dplyr::across( diff --git a/R/parse_params.R b/R/parse_params.R index ed5a2d2..4190c84 100644 --- a/R/parse_params.R +++ b/R/parse_params.R @@ -3,7 +3,7 @@ #' @param station_id character or numeric vector #' @param start start date or date time #' @param end end date or date time -#' @param hour logical; do `start` and `end` contain hours? +#' @param hour logical; is request for hourly data? #' @param real_time logical; is request for real-time data? #' #' @note If `hour = TRUE`, `start` and `end` can be character or POSIXct and diff --git a/R/retrieve_data.R b/R/retrieve_data.R index f9d584f..a166298 100644 --- a/R/retrieve_data.R +++ b/R/retrieve_data.R @@ -3,7 +3,7 @@ #' @param station_id character; in the format of "az01" #' @param start_f character; ISO formatted date time string #' @param time_interval character; ISO8601 formatted time interval string -#' @param endpoint character; one of "daily", "hourly", "hueto", or "fifteen" +#' @param endpoint character; one of "15min", "daily", "hourly", "hueto", "lw15min", or "lwdaily" #' @param print_call logical; when TRUE, prints the HTTP request to the AZMet API #' #' @return tibble From 304fc188a6152c1650618173f843741b293fb0c7 Mon Sep 17 00:00:00 2001 From: Jeremy Weiss Date: Wed, 10 Jul 2024 16:10:13 -0700 Subject: [PATCH 6/9] working on testing and errors --- R/parse_params.R | 16 +++++- tests/testthat/test-az_15min.R | 99 ++++++++++++++++++++++++++++++++ tests/testthat/test-az_lwdaily.R | 79 +++++++++++++++++++++++++ 3 files changed, 193 insertions(+), 1 deletion(-) create mode 100644 tests/testthat/test-az_15min.R create mode 100644 tests/testthat/test-az_lwdaily.R diff --git a/R/parse_params.R b/R/parse_params.R index 4190c84..9c7f9c3 100644 --- a/R/parse_params.R +++ b/R/parse_params.R @@ -220,13 +220,27 @@ parse_params <- function(station_id, start, end, hour = FALSE, real_time = FALSE # as one full hour. if (is.null(start)) { time_interval <- "*" - } else { + } else if (real_time == FALSE) { end_rounded <- lubridate::round_date(end_parsed, unit = "hour") start_rounded <- lubridate::round_date(start_parsed, unit = "hour") d <- lubridate::as.period(end_rounded - start_rounded) time_interval <- lubridate::format_ISO8601(d) + } else { # real_time == TRUE + end_rounded <- lubridate::round_date(end_parsed, unit = "minute") + start_rounded <- lubridate::round_date(start_parsed, unit = "minute") + d <- lubridate::as.period(end_parsed - start_parsed) + time_interval <- lubridate::format_ISO8601(d) } + #if (is.null(start)) { + # time_interval <- "*" + #} else { + # end_rounded <- lubridate::round_date(end_parsed, unit = "hour") + # start_rounded <- lubridate::round_date(start_parsed, unit = "hour") + # d <- lubridate::as.period(end_rounded - start_rounded) + # time_interval <- lubridate::format_ISO8601(d) + #} + # Return list # URLencode isn't strictly necessary, but it'll make the correct error print diff --git a/tests/testthat/test-az_15min.R b/tests/testthat/test-az_15min.R new file mode 100644 index 0000000..0218296 --- /dev/null +++ b/tests/testthat/test-az_15min.R @@ -0,0 +1,99 @@ +library(lubridate) +skip_if_offline() +skip_if_not(ping_service()) +skip_on_cran() + +test_that("start_date_time works as expected", { + suppressWarnings( + res <- az_15min( + station_id = 1, + start_date_time = paste0(lubridate::today(tzone = "America/Phoenix"), " 02"), + end_date_time = paste0(lubridate::today(tzone = "America/Phoenix"), " 03") + ) + ) + expect_equal(nrow(res), 4) +}) + +test_that("works with station_id as a vector", { + res <- + suppressWarnings( + az_15min( + station_id = c(1, 2), + start_date_time = paste0(lubridate::today(tzone = "America/Phoenix"), " 02"), + end_date_time = paste0(lubridate::today(tzone = "America/Phoenix"), " 03") + ) + ) + expect_s3_class(res, "data.frame") + expect_equal(unique(res$meta_station_id), c("az01", "az02")) +}) + +test_that("data is in correct format", { + res_default <- + suppressWarnings( + az_15min( + start_date_time = paste0(lubridate::today(tzone = "America/Phoenix"), " 02"), + end_date_time = paste0(lubridate::today(tzone = "America/Phoenix"), " 03") + ) + ) + expect_type(res_default$meta_station_name, "character") + expect_type(res_default$precip_total_mm, "double") + expect_s3_class(res_default$datetime, "POSIXct") +}) + +test_that("no data is returned as 0x0 tibble", { + skip("not sure how to reproduce this now that request for historical data error") + res_nodata <- + suppressWarnings(az_15min(start_date_time = "1980-01-01 00", end_date_time = "1980-01-02 00")) + expect_true(nrow(res_nodata) == 0) + expect_s3_class(res_nodata, "tbl_df") +}) + +test_that("requests with 23:59:59 work", { + h <- + suppressWarnings( + az_15min( + station_id = "az01", + start_date_time = paste0(lubridate::today(tzone = "America/Phoenix") - 1, " 23:00"), + end_date_time = paste0(lubridate::today(tzone = "America/Phoenix") - 1, " 23:59") + ) + ) + expect_equal(nrow(h), 4) +}) + +test_that("start=NULL, end=NULL works as expected", { + expect_message({ + null_null <- + suppressWarnings( + az_15min( + station_id = "az01" + ) + ) + }, glue::glue("Querying most recent datetime of 15-minute data")) + expect_equal(nrow(null_null), 1) +}) + +test_that("end=NULL works as expected", { + dt_start <- lubridate::now(tzone = "America/Phoenix") - lubridate::minutes(15) + end_null <- + suppressWarnings( + az_15min( + station_id = "az02", + start_date_time = dt_start + ) + ) + expect_equal(nrow(end_null), 1) +}) + +test_that("start as date only is rounded correctly", { + start_input <- lubridate::ymd(lubridate::today(tzone = "America/Phoenix")) + end_hour <- paste0(lubridate::today(tzone = "America/Phoenix"), " 01:00:00") + start_ymd <- + suppressWarnings( + az_15min( + station_id = "az01", + start_date_time = start_input, + end_date_time = end_hour + ) + ) + expect_equal(nrow(start_ymd), 4) +}) diff --git a/tests/testthat/test-az_lwdaily.R b/tests/testthat/test-az_lwdaily.R new file mode 100644 index 0000000..a3f198b --- /dev/null +++ b/tests/testthat/test-az_lwdaily.R @@ -0,0 +1,79 @@ +skip_if_offline() +skip_if_not(ping_service()) +skip_on_cran() + +test_that("numeric station_ids work", { + res_station <- az_lwdaily(station_id = 9) + expect_s3_class(res_station, "data.frame") +}) + +test_that("start_date works as expected", { + start <- "2024-07-01" + end <- "2024-07-07" + expect_message( + res_start <- az_lwdaily(station_id = 1, start_date = start, end_date = end), + "Querying data from 2024-07-01 through 2024-07-07" + ) + expect_equal(nrow(res_start), 7) +}) + +test_that("works with station_id as a vector", { + res_2 <- az_lwdaily(station_id = c(1, 2)) + expect_equal(unique(res_2$meta_station_id), c("az01", "az02")) + expect_s3_class(res_2, "data.frame") +}) + +test_that("data is in correct format", { + res_default <- az_lwdaily() + expect_type(res_default$meta_station_name, "character") + expect_type(res_default$dwpt_30cm_mean, "double") + expect_s3_class(res_default$date, "Date") +}) + +test_that("NAs converted correctly", { + res_missing <- az_lwdaily(station_id = 1, start_date = "2024-07-01", end_date = "2024-07-01") + expect_true(is.na(res_missing$dwpt_30cm_mean)) + expect_true(is.na(res_missing$lw1_total_wet_mins)) + expect_true(is.na(res_missing$relative_humidity_30cm_min)) + expect_true(is.na(res_missing$temp_air_30cm_maxC)) +}) + +test_that("no data is returned as 0x0 tibble", { + skip("Not sure how to reproduce this anymore now that these dates error") + suppressWarnings( + res_nodata <- + az_lwdaily(start_date = "1980-01-01", end_date = "1980-01-02") + ) + expect_true(nrow(res_nodata) == 0) + expect_s3_class(res_nodata, "tbl_df") +}) + +test_that("warn when some data missing", { + expect_warning( + az_lwdaily(station_id = "az32", start_date = "2023-07-01", end_date = "2024-07-01") + ) +}) + +test_that("start=NULL, end=NULL works correctly", { + null_null <- az_lwdaily(station_id = 2) + expect_equal(nrow(null_null), 1) +}) + +test_that("end=NULL works correctly", { + date_start <- lubridate::today(tzone = "America/Phoenix") - 2 + last_date <- date_start + 1 + expect_message( + date_null <- az_lwdaily(station_id = "az01", start_date = date_start), + glue::glue("Querying data from {date_start} through {last_date} ...") + ) + expect_message( + date_null <- az_lwdaily(station_id = "az01", start_date = date_start), + glue::glue("Returning data from {date_start}") + ) + expect_equal(date_null$date, seq(date_start, last_date, by = "day")) +}) + +test_that("start=NULL works correctly", { + last_date <- lubridate::today(tzone = "America/Phoenix") - 1 + expect_error(az_lwdaily(end = last_date), "If you supply `end_date`, you must also supply `start_date`") +}) From 356cff0c4202ddc4a63085d4953ab01d7c76d944 Mon Sep 17 00:00:00 2001 From: Jeremy Weiss Date: Fri, 12 Jul 2024 15:29:42 -0700 Subject: [PATCH 7/9] working on tests for `15min` and `lw15min` functions --- tests/testthat/test-az_15min.R | 10 +-- tests/testthat/test-az_lw15min.R | 101 +++++++++++++++++++++++++++++++ tests/testthat/test-az_lwdaily.R | 6 +- 3 files changed, 110 insertions(+), 7 deletions(-) create mode 100644 tests/testthat/test-az_lw15min.R diff --git a/tests/testthat/test-az_15min.R b/tests/testthat/test-az_15min.R index 0218296..d52f9d5 100644 --- a/tests/testthat/test-az_15min.R +++ b/tests/testthat/test-az_15min.R @@ -4,8 +4,8 @@ skip_if_not(ping_service()) skip_on_cran() test_that("start_date_time works as expected", { - suppressWarnings( - res <- az_15min( + res <- suppressWarnings( + az_15min( station_id = 1, start_date_time = paste0(lubridate::today(tzone = "America/Phoenix"), " 02"), end_date_time = paste0(lubridate::today(tzone = "America/Phoenix"), " 03") @@ -43,7 +43,9 @@ test_that("data is in correct format", { test_that("no data is returned as 0x0 tibble", { skip("not sure how to reproduce this now that request for historical data error") res_nodata <- - suppressWarnings(az_15min(start_date_time = "1980-01-01 00", end_date_time = "1980-01-02 00")) + suppressWarnings( + az_15min(start_date_time = "1980-01-01 00", end_date_time = "1980-01-02 00") + ) expect_true(nrow(res_nodata) == 0) expect_s3_class(res_nodata, "tbl_df") }) @@ -68,7 +70,7 @@ test_that("start=NULL, end=NULL works as expected", { station_id = "az01" ) ) - }, glue::glue("Querying most recent datetime of 15-minute data")) + }, glue::glue("Querying most recent datetime of 15-minute data ...")) expect_equal(nrow(null_null), 1) }) diff --git a/tests/testthat/test-az_lw15min.R b/tests/testthat/test-az_lw15min.R new file mode 100644 index 0000000..3187ede --- /dev/null +++ b/tests/testthat/test-az_lw15min.R @@ -0,0 +1,101 @@ +library(lubridate) +skip_if_offline() +skip_if_not(ping_service()) +skip_on_cran() + +test_that("start_date_time works as expected", { + res <- suppressWarnings( + az_lw15min( + station_id = 1, + start_date_time = paste0(lubridate::today(tzone = "America/Phoenix"), " 02"), + end_date_time = paste0(lubridate::today(tzone = "America/Phoenix"), " 03") + ) + ) + expect_equal(nrow(res), 5) +}) + +test_that("works with station_id as a vector", { + res <- + suppressWarnings( + az_lw15min( + station_id = c(1, 2), + start_date_time = paste0(lubridate::today(tzone = "America/Phoenix"), " 02"), + end_date_time = paste0(lubridate::today(tzone = "America/Phoenix"), " 03") + ) + ) + expect_s3_class(res, "data.frame") + expect_equal(unique(res$meta_station_id), c("az01", "az02")) +}) + +test_that("data is in correct format", { + res_default <- + suppressWarnings( + az_lw15min( + start_date_time = paste0(lubridate::today(tzone = "America/Phoenix"), " 02"), + end_date_time = paste0(lubridate::today(tzone = "America/Phoenix"), " 03") + ) + ) + expect_type(res_default$meta_station_name, "character") + expect_type(res_default$precip_total_mm, "double") + expect_s3_class(res_default$datetime, "POSIXct") +}) + +test_that("no data is returned as 0x0 tibble", { + skip("not sure how to reproduce this now that request for historical data error") + res_nodata <- + suppressWarnings( + az_lw15min(start_date_time = "1980-01-01 00", end_date_time = "1980-01-02 00") + ) + expect_true(nrow(res_nodata) == 0) + expect_s3_class(res_nodata, "tbl_df") +}) + +test_that("requests with 23:59:59 work", { + h <- + suppressWarnings( + az_lw15min( + station_id = "az01", + start_date_time = paste0(lubridate::today(tzone = "America/Phoenix") - 1, " 23:00"), + end_date_time = paste0(lubridate::today(tzone = "America/Phoenix") - 1, " 23:59") + ) + ) + expect_equal(nrow(h), 4) +}) + +test_that("start=NULL, end=NULL works as expected", { + expect_message({ + null_null <- + suppressWarnings( + az_lw15min( + station_id = "az01" + ) + ) + }, glue::glue("Querying most recent datetime of 15-minute data ...")) + expect_equal(nrow(null_null), 1) +}) + +test_that("end=NULL works as expected", { + dt_start <- lubridate::now(tzone = "America/Phoenix") - lubridate::minutes(15) + end_null <- + suppressWarnings( + az_lw15min( + station_id = "az02", + start_date_time = dt_start + ) + ) + expect_equal(nrow(end_null), 1) +}) + +test_that("start as date only is rounded correctly", { + start_input <- lubridate::ymd(lubridate::today(tzone = "America/Phoenix")) + end_hour <- paste0(lubridate::today(tzone = "America/Phoenix"), " 01:00:00") + start_ymd <- + suppressWarnings( + az_lw15min( + station_id = "az01", + start_date_time = start_input, + end_date_time = end_hour + ) + ) + expect_equal(nrow(start_ymd), 4) +}) diff --git a/tests/testthat/test-az_lwdaily.R b/tests/testthat/test-az_lwdaily.R index a3f198b..f069b89 100644 --- a/tests/testthat/test-az_lwdaily.R +++ b/tests/testthat/test-az_lwdaily.R @@ -40,10 +40,10 @@ test_that("NAs converted correctly", { test_that("no data is returned as 0x0 tibble", { skip("Not sure how to reproduce this anymore now that these dates error") - suppressWarnings( - res_nodata <- + res_nodata <- + suppressWarnings( az_lwdaily(start_date = "1980-01-01", end_date = "1980-01-02") - ) + ) expect_true(nrow(res_nodata) == 0) expect_s3_class(res_nodata, "tbl_df") }) From faad5ec60791c5cb7c2bcdacd27e2926b12f3f25 Mon Sep 17 00:00:00 2001 From: Jeremy Weiss Date: Wed, 17 Jul 2024 15:20:12 -0700 Subject: [PATCH 8/9] Finish `testthat` tests for three new functions, updated documentation --- NAMESPACE | 1 + R/az_15min.R | 4 +- R/az_add_units.R | 4 +- R/az_daily.R | 2 +- R/az_heat.R | 2 +- R/az_hourly.R | 2 +- R/az_lw15min.R | 4 +- R/az_lwdaily.R | 2 +- man/az_15min.Rd | 9 +++-- man/az_add_units.Rd | 4 +- man/az_daily.Rd | 33 +++++++++------- man/az_heat.Rd | 13 ++++--- man/az_hourly.Rd | 13 ++++--- man/az_lw15min.Rd | 11 +++--- man/az_lwdaily.Rd | 67 ++++++++++++++++++++++++++++++++ tests/testthat/test-az_hourly.R | 3 +- tests/testthat/test-az_lw15min.R | 10 ++--- 17 files changed, 129 insertions(+), 55 deletions(-) create mode 100644 man/az_lwdaily.Rd diff --git a/NAMESPACE b/NAMESPACE index 1cd1648..78a985d 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -7,5 +7,6 @@ export(az_daily) export(az_heat) export(az_hourly) export(az_lw15min) +export(az_lwdaily) importFrom(magrittr,"%>%") importFrom(rlang,.data) diff --git a/R/az_15min.R b/R/az_15min.R index 3e07909..e90c453 100755 --- a/R/az_15min.R +++ b/R/az_15min.R @@ -17,7 +17,7 @@ #' Defaults to the current date and time if left blank and `start_date_time` #' is specified. #' @details If neither `start_date_time` nor `end_date_time` are supplied, the -#' most recent date-time of data will be returned. If only `start_date_time` +#' most recent datetime of data will be returned. If only `start_date_time` #' is supplied, then `end_date_time` defaults to the current time. Supplying #' only `end_date_time` will result in an error. #' @note If `station_id` is supplied as a vector, multiple successive calls to @@ -25,7 +25,7 @@ #' the stations by leaving `station_id` blank and subsetting the resulting #' dataframe. Only the most recent 48 hours of 15-minute data are stored in #' the AZMet API. -#' @return a tibble. For units and other metadata, see +#' @return A tibble. For units and other metadata, see #' #' @seealso [az_daily()], [az_heat()], [az_hourly()], [az_lw15min()], [az_lwdaily()] #' @source diff --git a/R/az_add_units.R b/R/az_add_units.R index 996b344..29963e8 100644 --- a/R/az_add_units.R +++ b/R/az_add_units.R @@ -3,9 +3,9 @@ #' Assigns correct units to the output of `az_hourly()`, `az_daily()`, and #' `az_heat()` using the `units` package. #' -#' @param x a tibble output by [az_hourly()], [az_daily()], or [az_heat()] +#' @param x A tibble output by [az_hourly()], [az_daily()], or [az_heat()] #' -#' @return a tibble with columns of class "units" +#' @return A tibble with columns of class "units" #' @export #' #' @examples diff --git a/R/az_daily.R b/R/az_daily.R index 3e115d4..b334475 100644 --- a/R/az_daily.R +++ b/R/az_daily.R @@ -26,7 +26,7 @@ #' the stations by leaving `station_id` blank and subsetting the resulting #' dataframe. Requests for data from all stations for more than 6-12 months #' may take considerable time. -#' @return a tibble. For units and other metadata, see +#' @return A tibble. For units and other metadata, see #' #' @seealso [az_15min()], [az_heat()], [az_hourly()], [az_lw15min()], [az_lwdaily()] #' @source diff --git a/R/az_heat.R b/R/az_heat.R index 6edc152..6250e86 100644 --- a/R/az_heat.R +++ b/R/az_heat.R @@ -25,7 +25,7 @@ #' the API will be made. You may find better performance getting data for all #' the stations by leaving `station_id` blank and subsetting the resulting #' dataframe. -#' @return a tibble. For units and other metadata, see +#' @return A tibble. For units and other metadata, see #' #' @seealso [az_15min()], [az_daily()], [az_hourly()], [az_lw15min()], [az_lwdaily()] #' @source diff --git a/R/az_hourly.R b/R/az_hourly.R index 4c5e9af..c11ac3f 100644 --- a/R/az_hourly.R +++ b/R/az_hourly.R @@ -27,7 +27,7 @@ #' the stations by leaving `station_id` blank and subsetting the resulting #' dataframe. Requests for data from all stations for more than 10-15 days may #' take considerable time. -#' @return a tibble. For units and other metadata, see +#' @return A tibble. For units and other metadata, see #' #' @seealso [az_15min()], [az_daily()], [az_heat()], [az_lw15min()], [az_lwdaily()] #' @source diff --git a/R/az_lw15min.R b/R/az_lw15min.R index 50f4d45..464310d 100644 --- a/R/az_lw15min.R +++ b/R/az_lw15min.R @@ -18,7 +18,7 @@ #' Defaults to the current date and time if left blank and `start_date_time` #' is specified. #' @details If neither `start_date_time` nor `end_date_time` are supplied, the -#' most recent date-time of data will be returned. If only `start_date_time` +#' most recent datetime of data will be returned. If only `start_date_time` #' is supplied, then `end_date_time` defaults to the current time. Supplying #' only `end_date_time` will result in an error. #' @note If `station_id` is supplied as a vector, multiple successive calls to @@ -26,7 +26,7 @@ #' the stations by leaving `station_id` blank and subsetting the resulting #' dataframe. Only the most recent 48 hours of 15-minute data are stored in #' the AZMet API. -#' @return a tibble. For units and other metadata, see +#' @return A tibble. For units and other metadata, see #' #' @seealso [az_15min()], [az_daily()], [az_heat()], [az_hourly()], [az_lwdaily()] #' @source diff --git a/R/az_lwdaily.R b/R/az_lwdaily.R index bec33de..e412b21 100644 --- a/R/az_lwdaily.R +++ b/R/az_lwdaily.R @@ -26,7 +26,7 @@ #' the stations by leaving `station_id` blank and subsetting the resulting #' dataframe. Requests for data from all stations for more than 6-12 months #' may take considerable time. -#' @return a tibble. For units and other metadata, see +#' @return A tibble. For units and other metadata, see #' #' @seealso [az_15min()], [az_daily()], [az_heat()], [az_hourly()], [az_lw15min()] #' @source diff --git a/man/az_15min.Rd b/man/az_15min.Rd index 7b0d9ad..d7182a2 100644 --- a/man/az_15min.Rd +++ b/man/az_15min.Rd @@ -26,16 +26,17 @@ Defaults to the current date and time if left blank and \code{start_date_time} is specified.} } \value{ -a tibble. For units and other metadata, see +A tibble. For units and other metadata, see \url{https://azmet.arizona.edu/about} } \description{ Retrieves 15-minute data from the AZMet (Arizona Meteorological Network) API. -For a list of weather stations and their locations see \link{station_info}. +For a list of weather stations and their locations see \link{station_info}, or +visit https://azmet.arizona.edu/about. } \details{ If neither \code{start_date_time} nor \code{end_date_time} are supplied, the -most recent date-time of data will be returned. If only \code{start_date_time} +most recent datetime of data will be returned. If only \code{start_date_time} is supplied, then \code{end_date_time} defaults to the current time. Supplying only \code{end_date_time} will result in an error. } @@ -61,5 +62,5 @@ az_15min(start_date_time = "2022-09-25 01:00:00", end_date_time = "2022-09-25 07 } } \seealso{ -\code{\link[=az_daily]{az_daily()}}, \code{\link[=az_heat]{az_heat()}}, \code{\link[=az_hourly]{az_hourly()}}, \code{\link[=az_lw15min]{az_lw15min()}} +\code{\link[=az_daily]{az_daily()}}, \code{\link[=az_heat]{az_heat()}}, \code{\link[=az_hourly]{az_hourly()}}, \code{\link[=az_lw15min]{az_lw15min()}}, \code{\link[=az_lwdaily]{az_lwdaily()}} } diff --git a/man/az_add_units.Rd b/man/az_add_units.Rd index 8bd8291..81435c4 100644 --- a/man/az_add_units.Rd +++ b/man/az_add_units.Rd @@ -7,10 +7,10 @@ az_add_units(x) } \arguments{ -\item{x}{a tibble output by \code{\link[=az_hourly]{az_hourly()}}, \code{\link[=az_daily]{az_daily()}}, or \code{\link[=az_heat]{az_heat()}}} +\item{x}{A tibble output by \code{\link[=az_hourly]{az_hourly()}}, \code{\link[=az_daily]{az_daily()}}, or \code{\link[=az_heat]{az_heat()}}} } \value{ -a tibble with columns of class "units" +A tibble with columns of class "units" } \description{ Assigns correct units to the output of \code{az_hourly()}, \code{az_daily()}, and diff --git a/man/az_daily.Rd b/man/az_daily.Rd index 94ddc5c..036ed70 100644 --- a/man/az_daily.Rd +++ b/man/az_daily.Rd @@ -4,37 +4,41 @@ \alias{az_daily} \title{Retrieve Daily Weather Data from AZMET} \source{ -\url{https://ag.arizona.edu/azmet/} +\url{https://azmet.arizona.edu/} } \usage{ az_daily(station_id = NULL, start_date = NULL, end_date = NULL) } \arguments{ \item{station_id}{station ID can be supplied as numeric vector (e.g. -\code{station_id = c(8, 37)}) or as character vector with the prefix "az" and 2 -digits (e.g. \code{station_id = c("az08", "az37")}) If left blank data for all -stations will be returned} +\code{station_id = c(8, 37)}) or as character vector with the prefix "az" and +two digits (e.g. \code{station_id = c("az08", "az37")}). If left blank, data for all +stations will be returned.} \item{start_date}{A length-1 vector of class Date, POSIXct, or character in -YYYY-MM-DD format. Will be rounded \strong{down} to the nearest day if more -precision is supplied.} +YYYY-MM-DD format. Will be rounded \strong{down} to the nearest day if more +precision is supplied. Defaults to the day before the current date (i.e., +the most recent complete day) if left blank.} \item{end_date}{A length-1 vector of class Date, POSIXct, or character in -YYYY-MM-DD format. Will be rounded \strong{down} to the nearest day if more -precision is supplied. Defaults to the current date if left blank.} +YYYY-MM-DD format. Will be rounded \strong{down} to the nearest day if more +precision is supplied. Defaults to the day before the current date (i.e., +the most recent complete day) if left blank.} } \value{ -a tibble. For units and other metadata, see -\url{https://ag.arizona.edu/azmet/raw2003.htm} +A tibble. For units and other metadata, see +\url{https://azmet.arizona.edu/about} } \description{ Retrieves daily data from the Arizona Meteorological Network API. For a list -of weather stations and their locations see \link{station_info}. +of weather stations and their locations see \link{station_info}, or visit +https://azmet.arizona.edu/about. } \details{ If neither \code{start_date} nor \code{end_date} are supplied, the most recent -day of data will be returned. If only \code{start_date} is supplied, then the -end date defaults to the current date. Supplying only \code{end_date} will +day of data will be returned. If only \code{start_date} is supplied, then the +end date defaults to the day before the current date (i.e., +the most recent complete day). Supplying only \code{end_date} will result in an error. } \note{ @@ -57,8 +61,7 @@ az_daily(station_id = c("az01", "az02")) az_daily(start_date = "2022-09-25") az_daily(start_date = "2022-09-25", end_date = "2022-09-26") } - } \seealso{ -\code{\link[=az_15min]{az_15min()}}, \code{\link[=az_heat]{az_heat()}}, \code{\link[=az_hourly]{az_hourly()}}, \code{\link[=az_lw15min]{az_lw15min()}} +\code{\link[=az_15min]{az_15min()}}, \code{\link[=az_heat]{az_heat()}}, \code{\link[=az_hourly]{az_hourly()}}, \code{\link[=az_lw15min]{az_lw15min()}}, \code{\link[=az_lwdaily]{az_lwdaily()}} } diff --git a/man/az_heat.Rd b/man/az_heat.Rd index effa42c..6d02d8c 100644 --- a/man/az_heat.Rd +++ b/man/az_heat.Rd @@ -4,7 +4,7 @@ \alias{az_heat} \title{Retrieve Accumulated Heat Units and Evapotranspiration} \source{ -\url{https://ag.arizona.edu/azmet/} +\url{https://azmet.arizona.edu/} } \usage{ az_heat(station_id = NULL, start_date = NULL, end_date = NULL) @@ -26,14 +26,15 @@ an \code{end_date} is supplied, then data will be cumulative from the start of the year of \code{end_date}.} } \value{ -a tibble. For units and other metadata, see -\url{https://ag.arizona.edu/azmet/raw2003.htm} +A tibble. For units and other metadata, see +\url{https://azmet.arizona.edu/about} } \description{ Retrieves accumulated heat units and reference evapotranspiration units from -the Arizona Meteorological Network API. By default, returned values are +the Arizona Meteorological Network API. By default, returned values are cumulative since January 1 of the current year. For a list of weather -stations and their locations see \link{station_info}. +stations and their locations see \link{station_info}, or visit +https://azmet.arizona.edu/about. } \details{ Unlike \code{\link[=az_daily]{az_daily()}}, only one row of data per station is returned, @@ -67,5 +68,5 @@ az_heat(end_date = paste(yr, "03", "31", sep = "-")) } \seealso{ -\code{\link[=az_15min]{az_15min()}}, \code{\link[=az_daily]{az_daily()}}, \code{\link[=az_hourly]{az_hourly()}}, \code{\link[=az_lw15min]{az_lw15min()}} +\code{\link[=az_15min]{az_15min()}}, \code{\link[=az_daily]{az_daily()}}, \code{\link[=az_hourly]{az_hourly()}}, \code{\link[=az_lw15min]{az_lw15min()}}, \code{\link[=az_lwdaily]{az_lwdaily()}} } diff --git a/man/az_hourly.Rd b/man/az_hourly.Rd index 9519ea6..72e70f7 100644 --- a/man/az_hourly.Rd +++ b/man/az_hourly.Rd @@ -4,7 +4,7 @@ \alias{az_hourly} \title{Retrieve Hourly Weather Data} \source{ -\url{https://ag.arizona.edu/azmet/} +\url{https://azmet.arizona.edu/} } \usage{ az_hourly(station_id = NULL, start_date_time = NULL, end_date_time = NULL) @@ -12,7 +12,7 @@ az_hourly(station_id = NULL, start_date_time = NULL, end_date_time = NULL) \arguments{ \item{station_id}{station ID can be supplied as numeric vector (e.g. \code{station_id = c(8, 37)}) or as character vector with the prefix "az" and 2 -digits (e.g. \code{station_id = c("az08", "az37")}) If left blank data for all +digits (e.g. \code{station_id = c("az08", "az37")}) If left blank, data for all stations will be returned} \item{start_date_time}{A length-1 vector of class POSIXct or character in @@ -28,12 +28,13 @@ Defaults to the current date and time if left blank and \code{start_date_time} is specified.} } \value{ -a tibble. For units and other metadata, see -\url{https://ag.arizona.edu/azmet/raw2003.htm} +A tibble. For units and other metadata, see +\url{https://azmet.arizona.edu/about} } \description{ Retrieves hourly weather data from the Arizona Meteorological Network API. -For a list of weather stations and their locations see \link{station_info}. +For a list of weather stations and their locations see \link{station_info}, or +visit https://azmet.arizona.edu/about. } \details{ If neither \code{start_date_time} nor \code{end_date_time} are supplied, the @@ -64,5 +65,5 @@ az_hourly(start_date_time = "2022-09-25 01", end_date = "2022-09-25 20") } \seealso{ -\code{\link[=az_15min]{az_15min()}}, \code{\link[=az_daily]{az_daily()}}, \code{\link[=az_heat]{az_heat()}}, \code{\link[=az_lw15min]{az_lw15min()}} +\code{\link[=az_15min]{az_15min()}}, \code{\link[=az_daily]{az_daily()}}, \code{\link[=az_heat]{az_heat()}}, \code{\link[=az_lw15min]{az_lw15min()}}, \code{\link[=az_lwdaily]{az_lwdaily()}} } diff --git a/man/az_lw15min.Rd b/man/az_lw15min.Rd index 4d4befe..3933e8b 100644 --- a/man/az_lw15min.Rd +++ b/man/az_lw15min.Rd @@ -26,17 +26,18 @@ Defaults to the current date and time if left blank and \code{start_date_time} is specified.} } \value{ -a tibble. For units and other metadata, see +A tibble. For units and other metadata, see \url{https://azmet.arizona.edu/about} } \description{ Retrieves 15-minute leaf-wetness data from the AZMet (Arizona Meteorological -Network) API. Currently, these data only are available from stations in the -Yuma area. For a list of stations and their locations see \link{station_info}. +Network) API. Currently, these data only are available from weather stations +in the Yuma area. For a list of stations and their locations see +\link{station_info}, or visit https://azmet.arizona.edu/about. } \details{ If neither \code{start_date_time} nor \code{end_date_time} are supplied, the -most recent date-time of data will be returned. If only \code{start_date_time} +most recent datetime of data will be returned. If only \code{start_date_time} is supplied, then \code{end_date_time} defaults to the current time. Supplying only \code{end_date_time} will result in an error. } @@ -62,5 +63,5 @@ az_lw15min(start_date_time = "2022-09-25 01:00:00", end_date_time = "2022-09-25 } } \seealso{ -\code{\link[=az_15min]{az_15min()}}, \code{\link[=az_daily]{az_daily()}}, \code{\link[=az_heat]{az_heat()}}, \code{\link[=az_hourly]{az_hourly()}} +\code{\link[=az_15min]{az_15min()}}, \code{\link[=az_daily]{az_daily()}}, \code{\link[=az_heat]{az_heat()}}, \code{\link[=az_hourly]{az_hourly()}}, \code{\link[=az_lwdaily]{az_lwdaily()}} } diff --git a/man/az_lwdaily.Rd b/man/az_lwdaily.Rd new file mode 100644 index 0000000..be7f58c --- /dev/null +++ b/man/az_lwdaily.Rd @@ -0,0 +1,67 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/az_lwdaily.R +\name{az_lwdaily} +\alias{az_lwdaily} +\title{Retrieve Daily Leaf Wetness Data from AZMet} +\source{ +\url{https://azmet.arizona.edu/} +} +\usage{ +az_lwdaily(station_id = NULL, start_date = NULL, end_date = NULL) +} +\arguments{ +\item{station_id}{station ID can be supplied as numeric vector (e.g. +\code{station_id = c(8, 37)}) or as character vector with the prefix "az" and +two digits (e.g. \code{station_id = c("az08", "az37")}). If left blank, data for +all stations will be returned.} + +\item{start_date}{A length-1 vector of class Date, POSIXct, or character in +YYYY-MM-DD format. Will be rounded \strong{down} to the nearest day if more +precision is supplied. Defaults to the day before the current date (i.e., +the most recent complete day) if left blank.} + +\item{end_date}{A length-1 vector of class Date, POSIXct, or character in +YYYY-MM-DD format. Will be rounded \strong{down} to the nearest day if more +precision is supplied. Defaults to the day before the current date (i.e., +the most recent complete day) if left blank.} +} +\value{ +A tibble. For units and other metadata, see +\url{https://azmet.arizona.edu/about} +} +\description{ +Retrieves daily leaf wetness data from the Arizona Meteorological Network +API. Currently, these data only are available from weather stations in the +Yuma area. For a list of stations and their locations see \link{station_info}, or +visit https://azmet.arizona.edu/about. +} +\details{ +If neither \code{start_date} nor \code{end_date} are supplied, the most recent +day of data will be returned. If only \code{start_date} is supplied, then the +end date defaults to the day before the current date (i.e., the most recent +complete day). Supplying only \code{end_date} will result in an error. +} +\note{ +If \code{station_id} is supplied as a vector, multiple successive calls to +the API will be made. You may find better performance getting data for all +the stations by leaving \code{station_id} blank and subsetting the resulting +dataframe. Requests for data from all stations for more than 6-12 months +may take considerable time. +} +\examples{ +\dontrun{ +# Most recent data for all stations: +az_lwdaily() + +# Specify stations: +az_lwdaily(station_id = c(1, 2)) +az_lwdaily(station_id = c("az01", "az02")) + +# Specify dates: +az_lwdaily(start_date = "2022-09-25") +az_lwdaily(start_date = "2022-09-25", end_date = "2022-09-26") +} +} +\seealso{ +\code{\link[=az_15min]{az_15min()}}, \code{\link[=az_daily]{az_daily()}}, \code{\link[=az_heat]{az_heat()}}, \code{\link[=az_hourly]{az_hourly()}}, \code{\link[=az_lw15min]{az_lw15min()}} +} diff --git a/tests/testthat/test-az_hourly.R b/tests/testthat/test-az_hourly.R index 6cd7544..57a0ab5 100644 --- a/tests/testthat/test-az_hourly.R +++ b/tests/testthat/test-az_hourly.R @@ -58,7 +58,7 @@ test_that("start=NULL, end=NULL works as expected", { az_hourly( station_id = "az01" ) - }, glue::glue("Querying most recent hour of data")) + }, glue::glue("Querying most recent hour of data ...")) expect_equal(nrow(null_null), 1) #could be that current hour hasn't hit API yet. @@ -101,4 +101,3 @@ test_that("start as date only is rounded correctly", { ) expect_equal(min(date_null$date_datetime), start_actual) }) - diff --git a/tests/testthat/test-az_lw15min.R b/tests/testthat/test-az_lw15min.R index 3187ede..8c97b7c 100644 --- a/tests/testthat/test-az_lw15min.R +++ b/tests/testthat/test-az_lw15min.R @@ -36,7 +36,7 @@ test_that("data is in correct format", { ) ) expect_type(res_default$meta_station_name, "character") - expect_type(res_default$precip_total_mm, "double") + expect_type(res_default$temp_wetbulb_meanC, "double") expect_s3_class(res_default$datetime, "POSIXct") }) @@ -54,7 +54,7 @@ test_that("requests with 23:59:59 work", { h <- suppressWarnings( az_lw15min( - station_id = "az01", + station_id = "az02", start_date_time = paste0(lubridate::today(tzone = "America/Phoenix") - 1, " 23:00"), end_date_time = paste0(lubridate::today(tzone = "America/Phoenix") - 1, " 23:59") ) @@ -67,10 +67,10 @@ test_that("start=NULL, end=NULL works as expected", { null_null <- suppressWarnings( az_lw15min( - station_id = "az01" + station_id = "az02" ) ) - }, glue::glue("Querying most recent datetime of 15-minute data ...")) + }, glue::glue("Querying most recent datetime of leaf wetness 15-minute data ...")) expect_equal(nrow(null_null), 1) }) @@ -92,7 +92,7 @@ test_that("start as date only is rounded correctly", { start_ymd <- suppressWarnings( az_lw15min( - station_id = "az01", + station_id = "az02", start_date_time = start_input, end_date_time = end_hour ) From a0b8ec42fa33c6f144d4388f081ae77751d0318a Mon Sep 17 00:00:00 2001 From: Jeremy Weiss Date: Wed, 17 Jul 2024 15:21:53 -0700 Subject: [PATCH 9/9] update news with notes on three new download functions --- NEWS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/NEWS.md b/NEWS.md index 0860530..8e228fa 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,6 @@ # azmetr (development version) +- Added function `az_lwdaily()` for downloading daily leaf wetness data, which now are available via the API - Added function `az_lw15min()` for downloading 15-minute (a.k.a. "real-time") leaf wetness data, which now are available via the API - Added function `az_15min()` for downloading 15-minute (a.k.a. "real-time") data, which now are available via the API