diff --git a/.github/workflows/check-examples.yaml b/.github/workflows/check-examples.yaml index 95b0fc75..e33d7af5 100644 --- a/.github/workflows/check-examples.yaml +++ b/.github/workflows/check-examples.yaml @@ -3,8 +3,6 @@ on: push: branches: [main, master] - pull_request: - branches: [main, master] schedule: - cron: '27 17 * * 1,5' workflow_dispatch: diff --git a/CITATION.cff b/CITATION.cff index 9636d3c1..3c14c30f 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -192,9 +192,6 @@ references: email: jeroen@berkeley.edu orcid: https://orcid.org/0000-0002-4035-0289 year: '2024' - identifiers: - - type: url - value: https://arxiv.org/abs/1403.2805 version: '>= 1.7.0' - type: software title: rappdirs @@ -360,6 +357,19 @@ references: - family-names: Wickham given-names: Hadley year: '2024' +- type: software + title: mapSpain + abstract: 'mapSpain: Administrative Boundaries of Spain' + notes: Suggests + url: https://ropenspain.github.io/mapSpain/ + repository: https://CRAN.R-project.org/package=mapSpain + authors: + - family-names: Hernangómez + given-names: Diego + email: diego.hernangomezherrero@gmail.com + orcid: https://orcid.org/0000-0001-8457-4658 + affiliation: rOpenSpain + year: '2024' - type: software title: rmarkdown abstract: 'rmarkdown: Dynamic Documents for R' diff --git a/DESCRIPTION b/DESCRIPTION index f8ae1ca7..6cd593d2 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -38,15 +38,16 @@ Suggests: knitr, lifecycle, lubridate, + mapSpain, rmarkdown, scales, sf (>= 0.9.0), testthat (>= 3.0.0) VignetteBuilder: knitr -Config/Needs/website: mapSpain, classInt, terra, sf, gstat, geoR, - tidyverse, tidyterra, scales, gifski, reactable, leaflet, geofacet, - devtools, crosstalk, usethis +Config/Needs/website: classInt, terra, sf, gstat, geoR, tidyverse, + tidyterra, scales, gifski, reactable, leaflet, geofacet, devtools, + crosstalk, usethis Config/testthat/edition: 3 Config/testthat/parallel: true Copyright: © AEMET. See file COPYRIGHTS diff --git a/NAMESPACE b/NAMESPACE index a042da99..339a8d4e 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,11 +1,13 @@ # Generated by roxygen2: do not edit by hand export(aemet_api_key) +export(aemet_beaches) export(aemet_daily_clim) export(aemet_daily_period) export(aemet_daily_period_all) export(aemet_detect_api_key) export(aemet_extremes_clim) +export(aemet_forecast_beaches) export(aemet_forecast_daily) export(aemet_forecast_hourly) export(aemet_forecast_tidy) diff --git a/NEWS.md b/NEWS.md index d5f151e5..8ef8fdfb 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,12 +1,15 @@ # climaemet (development version) - Migrate from **httr** to **httr2** (#50). +- New functions for beaches: `aemet_forecast_beaches()` and `aemet_beaches()` + (#54). - Use progress bars in downloads thanks to **cli**. New argument `progress = TRUE` in most functions. - It is possible to use several API keys to avoid API throttling, see `?climaemet::aemet_api_key` (#53). - New helper function `dms2decdegrees_2()`. - Update `aemet_munic` with January 2024 data. +- New package in 'Suggests': **mapSpain**. # climaemet 1.2.1 diff --git a/R/aemet_beaches.R b/R/aemet_beaches.R new file mode 100644 index 00000000..cd337c70 --- /dev/null +++ b/R/aemet_beaches.R @@ -0,0 +1,108 @@ +# valores-climatologicos +# https://opendata.aemet.es/dist/index.html#/ + +#' AEMET beaches +#' +#' Get AEMET beaches. +#' +#' @family aemet_api_data +#' +#' +#' @inheritParams aemet_daily_clim +#' +#' @inheritParams aemet_last_obs +#' +#' @return A [`tibble`][tibble::tibble()] or a \CRANpkg{sf} object. +#' +#' @inheritSection aemet_daily_clim API Key +#' +#' @seealso [aemet_forecast_beaches()] +#' +#' @details +#' The first result of the API call on each session is (temporarily) cached in +#' the assigned [tempdir()] for avoiding unneeded API calls. +#' +#' @examplesIf aemet_detect_api_key() +#' library(tibble) +#' beaches <- aemet_beaches() +#' beaches +#' +#' # Cached during this R session +#' beaches2 <- aemet_beaches(verbose = TRUE) +#' +#' identical(beaches, beaches2) +#' +#' # Select an map beaches +#' library(dplyr) +#' library(ggplot2) +#' library(mapSpain) +#' +#' # Alicante / Alacant +#' beaches_sf <- aemet_beaches(return_sf = TRUE) %>% +#' filter(ID_PROVINCIA == "03") +#' +#' prov <- mapSpain::esp_get_prov("Alicante") +#' +#' ggplot(prov) + +#' geom_sf() + +#' geom_sf( +#' data = beaches_sf, shape = 4, size = 2.5, +#' color = "blue" +#' ) +#' +#' @export +aemet_beaches <- function(verbose = FALSE, return_sf = FALSE) { + # Validate inputs---- + stopifnot(is.logical(verbose)) + stopifnot(is.logical(return_sf)) + + cached_df <- file.path(tempdir(), "aemet_beaches.rds") + cached_date <- file.path(tempdir(), "aemet_beaches_date.rds") + + if (file.exists(cached_df)) { + df <- readRDS(cached_df) + dat <- readRDS(cached_date) + + if (verbose) { + message( + "Loading beaches from temporal cached file saved at ", + format(dat, usetz = TRUE) + ) + } + } else { + # download beaches + url <- paste0( + "https://www.aemet.es/documentos/es/eltiempo/", + "prediccion/playas/Playas_codigos.csv" + ) + r <- httr2::request(url) + r <- httr2::req_perform(r) + body <- httr2::resp_body_raw(r) + df <- readr::read_delim(body, + delim = ";", + show_col_types = FALSE, + locale = readr::locale( + encoding = "ISO-8859-1" + ), + trim_ws = TRUE + ) + + # Formats---- + + df$longitud <- vapply(df$LONGITUD, dms2decdegrees_2, FUN.VALUE = numeric(1)) + df$latitud <- vapply(df$LATITUD, dms2decdegrees_2, FUN.VALUE = numeric(1)) + + + + # Cache on temp dir + saveRDS(df, cached_df) + saveRDS(Sys.time(), cached_date) + } + + # Validate sf---- + if (return_sf) { + df <- aemet_hlp_sf(df, "latitud", "longitud", verbose) + } + + return(df) +} diff --git a/R/aemet_forecast_beach.R b/R/aemet_forecast_beach.R new file mode 100644 index 00000000..161b2937 --- /dev/null +++ b/R/aemet_forecast_beach.R @@ -0,0 +1,202 @@ +#' Forecast database for beaches +#' +#' Get a database of daily weather forecasts for a beach. Beach database can +#' be accessed with [aemet_beaches()]. +#' +#' @family aemet_api_data +#' @family forecasts +#' +#' @param x A vector of beaches codes to extract. See [aemet_beaches()]. +#' @inheritParams get_data_aemet +#' @inheritParams aemet_last_obs +#' +#' @inheritSection aemet_daily_clim API Key +#' +#' @return A [`tibble`][tibble::tibble()] or a \CRANpkg{sf} object. +#' +#' @export +#' @seealso +#' [aemet_beaches()] for municipality codes. +#' +#' +#' @examplesIf aemet_detect_api_key() +#' # Forecast for beaches in Palma, Mallorca +#' library(dplyr) +#' library(ggplot2) +#' +#' palma_b <- aemet_beaches() %>% +#' filter(ID_MUNICIPIO == "07040") +#' +#' forecast_b <- aemet_forecast_beaches(palma_b$ID_PLAYA) +#' glimpse(forecast_b) +#' +#' ggplot(forecast_b) + +#' geom_line(aes(fecha, tagua_valor1, color = nombre)) + +#' facet_wrap(~nombre, ncol = 1) + +#' labs( +#' title = "Water temperature in beaches of Palma (ES)", +#' subtitle = "Forecast 3-days", +#' x = "Date", +#' y = "Temperature (Celsius)", +#' color = "Beach" +#' ) +aemet_forecast_beaches <- function(x, verbose = FALSE, return_sf = FALSE, + extract_metadata = FALSE, progress = TRUE) { + # 1. API call ----- + + ## Metadata ---- + if (extract_metadata) { + mun <- aemet_beaches() + x <- mun$ID_PLAYA[1] + + meta <- get_metadata_aemet( + apidest = paste0("/api/prediccion/especifica/playa/", x), + verbose = verbose + ) + meta <- aemet_hlp_meta_forecast(meta) + return(meta) + } + + ## Normal call ---- + + # Make calls on loop for progress bar + final_result <- list() # Store results + + # Deactive progressbar if verbose + if (verbose) progress <- FALSE + if (!cli::is_dynamic_tty()) progress <- FALSE + + # nolint start + # nocov start + if (progress) { + opts <- options() + options( + cli.progress_bar_style = "fillsquares", + cli.progress_show_after = 3, + cli.spinner = "clock" + ) + + cli::cli_progress_bar( + format = paste0( + "{cli::pb_spin} AEMET API ({cli::pb_current}/{cli::pb_total}) ", + "| {cli::pb_bar} {cli::pb_percent} ", + "| ETA:{cli::pb_eta} [{cli::pb_elapsed}]" + ), + total = length(x), clear = FALSE + ) + } + + # nocov end + # nolint end + + for (id in x) { + if (progress) cli::cli_progress_update() # nocov + df <- try(aemet_forecast_beach_single(id, verbose = verbose), silent = TRUE) + + if (inherits(df, "try-error")) { + message( + "\nAEMET API call for '", id, "' returned an error\n", + "Return NULL for this query" + ) + + df <- NULL + } + + final_result <- c(final_result, list(df)) + } + + + # nolint start + # nocov start + if (progress) { + cli::cli_progress_done() + options( + cli.progress_bar_style = opts$cli.progress_bar_style, + cli.progress_show_after = opts$cli.progress_show_after, + cli.spinner = opts$cli.spinner + ) + } + # nocov end + # nolint end + + + + # Final tweaks + final_result <- dplyr::bind_rows(final_result) + # Preserve format + final_result$id <- sprintf("%07d", as.numeric(final_result$id)) + final_result <- dplyr::as_tibble(final_result) + final_result <- dplyr::distinct(final_result) + final_result <- aemet_hlp_guess(final_result, + preserve = c("id", "localidad") + ) + + + # Check spatial---- + if (return_sf) { + # Coordinates from beaches + sf_beaches <- aemet_beaches(verbose = verbose, return_sf = FALSE) + sf_beaches <- sf_beaches[c("ID_PLAYA", "latitud", "longitud")] + names(sf_beaches) <- c("id", "latitud", "longitud") + final_result <- dplyr::left_join(final_result, sf_beaches, + by = "id" + ) + final_result <- aemet_hlp_sf(final_result, "latitud", "longitud", verbose) + } + + final_result +} + +aemet_forecast_beach_single <- function(x, verbose = FALSE) { + if (is.numeric(x)) x <- sprintf("%07d", x) + + pred <- get_data_aemet( + apidest = paste0("/api/prediccion/especifica/playa/", x), + verbose = verbose + ) + + pred$elaborado <- as.POSIXct(gsub("T", " ", pred$elaborado), + tz = "Europe/Madrid" + ) + + # Unnesting this dataset is complex + col_types <- get_col_first_class(pred) + vars <- names(col_types[col_types %in% c("list", "data.frame")]) + + first_lev <- tidyr::unnest(pred, + col = dplyr::all_of(vars), names_sep = "_", + keep_empty = TRUE + ) + + # Extract prediccion dia + pred_dia <- first_lev$prediccion_dia[[1]] + master <- first_lev[, names(first_lev) != "prediccion_dia"] + + vars_prd <- names(pred_dia) + pred_dia <- tidyr::unnest(pred_dia, + col = dplyr::all_of(vars_prd), + names_sep = "_", + keep_empty = TRUE + ) + + # Adjust + pred_dia$fecha <- as.Date(as.character(pred_dia$fecha), + tryFormats = c("%Y-%m-%d", "%Y/%m/%d", "%Y%m%d") + ) + pred_dia <- tibble::as_tibble(pred_dia) + + master_end <- dplyr::bind_cols(master, pred_dia) + + # Adjust ids + master_end$id <- sprintf("%07d", master_end$id) + master_end$localidad <- sprintf("%05d", master_end$localidad) + master_end <- dplyr::relocate(master_end, + dplyr::all_of(c("id", "localidad", "fecha")), + .before = dplyr::all_of("nombre") + ) + # clean up + master_end <- master_end[!grepl("^origen", names(master_end))] + + + return(master_end) +} diff --git a/R/aemet_forecast_hourly.R b/R/aemet_forecast_hourly.R index 1cd8bfdb..100829ab 100644 --- a/R/aemet_forecast_hourly.R +++ b/R/aemet_forecast_hourly.R @@ -24,7 +24,7 @@ #' @seealso #' [aemet_munic] for municipality codes and \CRANpkg{mapSpain} package for #' working with `sf` objects of municipalities (see -#' `mapSpain::esp_get_munic()`). +#' [mapSpain::esp_get_munic()] and **Examples**). #' #' #' @details @@ -44,10 +44,7 @@ #' data("aemet_munic") #' library(dplyr) #' munis <- aemet_munic %>% -#' filter(municipio_nombre %in% c( -#' "Santiago de Compostela", -#' "Lugo" -#' )) %>% +#' filter(municipio_nombre %in% c("Santiago de Compostela", "Lugo")) %>% #' pull(municipio) #' #' daily <- aemet_forecast_daily(munis) @@ -104,6 +101,31 @@ #' format(daily_temp_end$elaborado[1], usetz = TRUE) #' ) #' ) +#' +#' # Spatial with mapSpain +#' library(mapSpain) +#' library(sf) +#' +#' lugo_sf <- esp_get_munic(munic = "Lugo") %>% +#' select(LAU_CODE) +#' +#' daily_temp_end_lugo_sf <- daily_temp_end %>% +#' filter(nombre == "Lugo" & name == "temperatura_maxima") %>% +#' # Join by LAU_CODE +#' left_join(lugo_sf, by = c("municipio" = "LAU_CODE")) %>% +#' st_as_sf() +#' +#' ggplot(daily_temp_end_lugo_sf) + +#' geom_sf(aes(fill = value)) + +#' facet_wrap(~fecha) + +#' scale_fill_gradientn( +#' colors = c("blue", "red"), +#' guide = guide_legend() +#' ) + +#' labs( +#' main = "Forecast: 7-day max temperature", +#' subtitle = "Lugo, ES" +#' ) aemet_forecast_hourly <- function(x, verbose = FALSE, extract_metadata = FALSE, progress = TRUE) { # 1. API call ----- diff --git a/README.Rmd b/README.Rmd index faf9f8ee..cf4d3319 100644 --- a/README.Rmd +++ b/README.Rmd @@ -152,7 +152,10 @@ data_observation <- aemet_last_obs(station) knitr::kable(head(data_observation)) ## Get daily/annual climatology values for a station -data_daily <- aemet_daily_clim(station, start = "2022-01-01", end = "2022-06-30") +data_daily <- aemet_daily_clim(station, + start = "2022-01-01", + end = "2022-06-30" +) knitr::kable(head(data_daily)) diff --git a/README.md b/README.md index c645faf4..eff0392a 100644 --- a/README.md +++ b/README.md @@ -119,21 +119,22 @@ library(climaemet) # See a tibble in action aemet_last_obs("9434") -#> # A tibble: 12 × 25 +#> # A tibble: 13 × 25 #> idema lon fint prec alt vmax vv dv lat dmax #> -#> 1 9434 -1.00 2024-06-21 21:00:00 0 249 3.5 2.1 321 41.7 330 -#> 2 9434 -1.00 2024-06-21 22:00:00 0 249 4.6 3.6 264 41.7 263 -#> 3 9434 -1.00 2024-06-21 23:00:00 0 249 4.1 3 257 41.7 270 -#> 4 9434 -1.00 2024-06-22 00:00:00 0 249 4.7 2.3 262 41.7 288 -#> 5 9434 -1.00 2024-06-22 01:00:00 0 249 4.3 2.6 315 41.7 240 -#> 6 9434 -1.00 2024-06-22 02:00:00 0 249 6.2 5 292 41.7 298 -#> 7 9434 -1.00 2024-06-22 03:00:00 0 249 6.8 4.4 296 41.7 288 -#> 8 9434 -1.00 2024-06-22 04:00:00 0 249 5.5 3.5 305 41.7 293 -#> 9 9434 -1.00 2024-06-22 05:00:00 0 249 5.6 2.5 302 41.7 310 -#> 10 9434 -1.00 2024-06-22 06:00:00 0 249 5.5 4.3 312 41.7 315 -#> 11 9434 -1.00 2024-06-22 07:00:00 0 249 7.2 4.9 302 41.7 303 -#> 12 9434 -1.00 2024-06-22 08:00:00 0 249 8.1 6.1 297 41.7 293 +#> 1 9434 -1.00 2024-06-22 21:00:00 0 249 9.7 6.3 323 41.7 333 +#> 2 9434 -1.00 2024-06-22 22:00:00 0 249 10.5 6.9 302 41.7 310 +#> 3 9434 -1.00 2024-06-22 23:00:00 0 249 10.5 5.8 305 41.7 308 +#> 4 9434 -1.00 2024-06-23 00:00:00 0 249 11 8.4 305 41.7 318 +#> 5 9434 -1.00 2024-06-23 01:00:00 0 249 11.8 8.5 296 41.7 290 +#> 6 9434 -1.00 2024-06-23 02:00:00 0 249 12.2 8 304 41.7 298 +#> 7 9434 -1.00 2024-06-23 03:00:00 0 249 12.6 9.3 301 41.7 305 +#> 8 9434 -1.00 2024-06-23 04:00:00 0 249 13.2 10.1 302 41.7 303 +#> 9 9434 -1.00 2024-06-23 05:00:00 0 249 12.5 7.4 292 41.7 305 +#> 10 9434 -1.00 2024-06-23 06:00:00 0 249 15.5 11.5 297 41.7 298 +#> 11 9434 -1.00 2024-06-23 07:00:00 0 249 15.4 11.7 305 41.7 303 +#> 12 9434 -1.00 2024-06-23 08:00:00 0 249 16.1 10.5 312 41.7 308 +#> 13 9434 -1.00 2024-06-23 09:00:00 0 249 16.3 10.7 315 41.7 310 #> # ℹ 15 more variables: ubi , pres , hr , stdvv , ts , #> # pres_nmar , tamin , ta , tamax , tpr , #> # stddv , inso , tss5cm , pacutp , tss20cm @@ -172,17 +173,20 @@ knitr::kable(head(data_observation)) | idema | lon | fint | prec | alt | vmax | vv | dv | lat | dmax | ubi | pres | hr | stdvv | ts | pres_nmar | tamin | ta | tamax | tpr | stddv | inso | tss5cm | pacutp | tss20cm | |:------|----------:|:--------------------|-----:|----:|-----:|----:|----:|---------:|-----:|:--------------------|------:|----:|------:|-----:|----------:|------:|-----:|------:|-----:|------:|-----:|-------:|-------:|--------:| -| 9434 | -1.004167 | 2024-06-21 21:00:00 | 0 | 249 | 3.5 | 2.1 | 321 | 41.66056 | 330 | ZARAGOZA AEROPUERTO | 991.3 | 45 | 0.4 | 21.8 | 1020.4 | 23.2 | 23.2 | 23.5 | 10.6 | 10 | 0 | 29.0 | 0 | 29.5 | -| 9434 | -1.004167 | 2024-06-21 22:00:00 | 0 | 249 | 4.6 | 3.6 | 264 | 41.66056 | 263 | ZARAGOZA AEROPUERTO | 991.8 | 53 | 0.4 | 21.0 | 1021.1 | 21.1 | 21.1 | 23.2 | 11.1 | 6 | 0 | 28.0 | 0 | 29.4 | -| 9434 | -1.004167 | 2024-06-21 23:00:00 | 0 | 249 | 4.1 | 3.0 | 257 | 41.66056 | 270 | ZARAGOZA AEROPUERTO | 991.8 | 54 | 0.3 | 20.1 | 1021.2 | 20.6 | 20.6 | 21.2 | 11.0 | 6 | 0 | 27.2 | 0 | 29.1 | -| 9434 | -1.004167 | 2024-06-22 00:00:00 | 0 | 249 | 4.7 | 2.3 | 262 | 41.66056 | 288 | ZARAGOZA AEROPUERTO | 991.8 | 55 | 0.4 | 18.7 | 1021.2 | 19.8 | 19.8 | 20.6 | 10.5 | 11 | 0 | 26.5 | 0 | 28.8 | -| 9434 | -1.004167 | 2024-06-22 01:00:00 | 0 | 249 | 4.3 | 2.6 | 315 | 41.66056 | 240 | ZARAGOZA AEROPUERTO | 991.6 | 60 | 0.3 | 18.2 | 1021.1 | 18.9 | 18.9 | 20.4 | 11.0 | 9 | 0 | 25.8 | 0 | 28.5 | -| 9434 | -1.004167 | 2024-06-22 02:00:00 | 0 | 249 | 6.2 | 5.0 | 292 | 41.66056 | 298 | ZARAGOZA AEROPUERTO | 991.4 | 64 | 0.5 | 18.6 | 1020.9 | 18.3 | 18.8 | 18.9 | 11.9 | 5 | 0 | 25.2 | 0 | 28.2 | +| 9434 | -1.004167 | 2024-06-22 21:00:00 | 0 | 249 | 9.7 | 6.3 | 323 | 41.66056 | 333 | ZARAGOZA AEROPUERTO | 992.0 | 56 | 1.1 | 19.8 | 1021.5 | 19.2 | 19.2 | 19.8 | 10.2 | 10 | 0 | 28.3 | 0 | 29.3 | +| 9434 | -1.004167 | 2024-06-22 22:00:00 | 0 | 249 | 10.5 | 6.9 | 302 | 41.66056 | 310 | ZARAGOZA AEROPUERTO | 991.9 | 57 | 0.8 | 19.8 | 1021.4 | 19.1 | 19.3 | 19.3 | 10.5 | 7 | 0 | 27.6 | 0 | 29.1 | +| 9434 | -1.004167 | 2024-06-22 23:00:00 | 0 | 249 | 10.5 | 5.8 | 305 | 41.66056 | 308 | ZARAGOZA AEROPUERTO | 991.6 | 60 | 1.0 | 18.7 | 1021.2 | 18.5 | 18.5 | 19.3 | 10.5 | 8 | 0 | 26.9 | 0 | 28.8 | +| 9434 | -1.004167 | 2024-06-23 00:00:00 | 0 | 249 | 11.0 | 8.4 | 305 | 41.66056 | 318 | ZARAGOZA AEROPUERTO | 991.1 | 60 | 1.0 | 18.7 | 1020.7 | 18.5 | 18.5 | 18.7 | 10.5 | 6 | 0 | 26.2 | 0 | 28.6 | +| 9434 | -1.004167 | 2024-06-23 01:00:00 | 0 | 249 | 11.8 | 8.5 | 296 | 41.66056 | 290 | ZARAGOZA AEROPUERTO | 990.6 | 62 | 1.0 | 18.1 | 1020.2 | 17.9 | 18.0 | 18.5 | 10.6 | 6 | 0 | 25.7 | 0 | 28.3 | +| 9434 | -1.004167 | 2024-06-23 02:00:00 | 0 | 249 | 12.2 | 8.0 | 304 | 41.66056 | 298 | ZARAGOZA AEROPUERTO | 990.1 | 62 | 1.4 | 17.8 | 1019.7 | 17.8 | 17.8 | 18.1 | 10.4 | 11 | 0 | 25.1 | 0 | 28.0 | ``` r ## Get daily/annual climatology values for a station -data_daily <- aemet_daily_clim(station, start = "2022-01-01", end = "2022-06-30") +data_daily <- aemet_daily_clim(station, + start = "2022-01-01", + end = "2022-06-30" +) knitr::kable(head(data_daily)) ``` diff --git a/codemeta.json b/codemeta.json index 13749abc..e88ae998 100644 --- a/codemeta.json +++ b/codemeta.json @@ -135,6 +135,18 @@ }, "sameAs": "https://CRAN.R-project.org/package=lubridate" }, + { + "@type": "SoftwareApplication", + "identifier": "mapSpain", + "name": "mapSpain", + "provider": { + "@id": "https://cran.r-project.org", + "@type": "Organization", + "name": "Comprehensive R Archive Network (CRAN)", + "url": "https://cran.r-project.org" + }, + "sameAs": "https://CRAN.R-project.org/package=mapSpain" + }, { "@type": "SoftwareApplication", "identifier": "rmarkdown", @@ -327,7 +339,7 @@ }, "applicationCategory": "Meteorology", "isPartOf": "https://ropenspain.es/", - "fileSize": "827.009KB", + "fileSize": "831.468KB", "citation": [ { "@type": "SoftwareSourceCode", diff --git a/man/aemet_beaches.Rd b/man/aemet_beaches.Rd new file mode 100644 index 00000000..5e0d8744 --- /dev/null +++ b/man/aemet_beaches.Rd @@ -0,0 +1,75 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/aemet_beaches.R +\name{aemet_beaches} +\alias{aemet_beaches} +\title{AEMET beaches} +\usage{ +aemet_beaches(verbose = FALSE, return_sf = FALSE) +} +\arguments{ +\item{verbose}{Logical \code{TRUE/FALSE}. Provides information about the flow of +information between the client and server.} + +\item{return_sf}{Logical \code{TRUE} or \code{FALSE}. +Should the function return an \code{\link[sf:sf]{sf}} spatial object? If \code{FALSE} +(the default value) it returns a \code{\link[tibble:tibble]{tibble}}. Note that +you need to have the \CRANpkg{sf} package installed.} +} +\value{ +A \code{\link[tibble:tibble]{tibble}} or a \CRANpkg{sf} object. +} +\description{ +Get AEMET beaches. +} +\details{ +The first result of the API call on each session is (temporarily) cached in +the assigned \code{\link[=tempdir]{tempdir()}} for avoiding unneeded API calls. +} +\section{API Key}{ +You need to set your API Key globally using \code{\link[=aemet_api_key]{aemet_api_key()}}. +} + +\examples{ +\dontshow{if (aemet_detect_api_key()) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} +library(tibble) +beaches <- aemet_beaches() +beaches + +# Cached during this R session +beaches2 <- aemet_beaches(verbose = TRUE) + +identical(beaches, beaches2) + +# Select an map beaches +library(dplyr) +library(ggplot2) +library(mapSpain) + +# Alicante / Alacant +beaches_sf <- aemet_beaches(return_sf = TRUE) \%>\% + filter(ID_PROVINCIA == "03") + +prov <- mapSpain::esp_get_prov("Alicante") + +ggplot(prov) + + geom_sf() + + geom_sf( + data = beaches_sf, shape = 4, size = 2.5, + color = "blue" + ) +\dontshow{\}) # examplesIf} +} +\seealso{ +\code{\link[=aemet_forecast_beaches]{aemet_forecast_beaches()}} + +Other aemet_api_data: +\code{\link{aemet_daily_clim}()}, +\code{\link{aemet_extremes_clim}()}, +\code{\link{aemet_forecast_beaches}()}, +\code{\link{aemet_forecast_daily}()}, +\code{\link{aemet_last_obs}()}, +\code{\link{aemet_monthly}}, +\code{\link{aemet_normal}}, +\code{\link{aemet_stations}()} +} +\concept{aemet_api_data} diff --git a/man/aemet_daily.Rd b/man/aemet_daily.Rd index 9c05c852..1622181b 100644 --- a/man/aemet_daily.Rd +++ b/man/aemet_daily.Rd @@ -95,7 +95,9 @@ glimpse(meta$campos) \code{\link[=aemet_api_key]{aemet_api_key()}}, \code{\link[=as.Date]{as.Date()}} Other aemet_api_data: +\code{\link{aemet_beaches}()}, \code{\link{aemet_extremes_clim}()}, +\code{\link{aemet_forecast_beaches}()}, \code{\link{aemet_forecast_daily}()}, \code{\link{aemet_last_obs}()}, \code{\link{aemet_monthly}}, diff --git a/man/aemet_extremes_clim.Rd b/man/aemet_extremes_clim.Rd index 9ff45f45..a06987c8 100644 --- a/man/aemet_extremes_clim.Rd +++ b/man/aemet_extremes_clim.Rd @@ -57,7 +57,9 @@ glimpse(obs) \code{\link[=aemet_api_key]{aemet_api_key()}} Other aemet_api_data: +\code{\link{aemet_beaches}()}, \code{\link{aemet_daily_clim}()}, +\code{\link{aemet_forecast_beaches}()}, \code{\link{aemet_forecast_daily}()}, \code{\link{aemet_last_obs}()}, \code{\link{aemet_monthly}}, diff --git a/man/aemet_forecast.Rd b/man/aemet_forecast.Rd index 8d737946..8415720a 100644 --- a/man/aemet_forecast.Rd +++ b/man/aemet_forecast.Rd @@ -63,10 +63,7 @@ You need to set your API Key globally using \code{\link[=aemet_api_key]{aemet_ap data("aemet_munic") library(dplyr) munis <- aemet_munic \%>\% - filter(municipio_nombre \%in\% c( - "Santiago de Compostela", - "Lugo" - )) \%>\% + filter(municipio_nombre \%in\% c("Santiago de Compostela", "Lugo")) \%>\% pull(municipio) daily <- aemet_forecast_daily(munis) @@ -123,22 +120,50 @@ ggplot(daily_temp_end) + format(daily_temp_end$elaborado[1], usetz = TRUE) ) ) + +# Spatial with mapSpain +library(mapSpain) +library(sf) + +lugo_sf <- esp_get_munic(munic = "Lugo") \%>\% + select(LAU_CODE) + +daily_temp_end_lugo_sf <- daily_temp_end \%>\% + filter(nombre == "Lugo" & name == "temperatura_maxima") \%>\% + # Join by LAU_CODE + left_join(lugo_sf, by = c("municipio" = "LAU_CODE")) \%>\% + st_as_sf() + +ggplot(daily_temp_end_lugo_sf) + + geom_sf(aes(fill = value)) + + facet_wrap(~fecha) + + scale_fill_gradientn( + colors = c("blue", "red"), + guide = guide_legend() + ) + + labs( + main = "Forecast: 7-day max temperature", + subtitle = "Lugo, ES" + ) \dontshow{\}) # examplesIf} } \seealso{ \link{aemet_munic} for municipality codes and \CRANpkg{mapSpain} package for working with \code{sf} objects of municipalities (see -\code{mapSpain::esp_get_munic()}). +\code{\link[mapSpain:esp_get_munic]{mapSpain::esp_get_munic()}} and \strong{Examples}). Other aemet_api_data: +\code{\link{aemet_beaches}()}, \code{\link{aemet_daily_clim}()}, \code{\link{aemet_extremes_clim}()}, +\code{\link{aemet_forecast_beaches}()}, \code{\link{aemet_last_obs}()}, \code{\link{aemet_monthly}}, \code{\link{aemet_normal}}, \code{\link{aemet_stations}()} Other forecasts: +\code{\link{aemet_forecast_beaches}()}, \code{\link{aemet_forecast_tidy}()} } \concept{aemet_api_data} diff --git a/man/aemet_forecast_beaches.Rd b/man/aemet_forecast_beaches.Rd new file mode 100644 index 00000000..f568287a --- /dev/null +++ b/man/aemet_forecast_beaches.Rd @@ -0,0 +1,86 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/aemet_forecast_beach.R +\name{aemet_forecast_beaches} +\alias{aemet_forecast_beaches} +\title{Forecast database for beaches} +\usage{ +aemet_forecast_beaches( + x, + verbose = FALSE, + return_sf = FALSE, + extract_metadata = FALSE, + progress = TRUE +) +} +\arguments{ +\item{x}{A vector of beaches codes to extract. See \code{\link[=aemet_beaches]{aemet_beaches()}}.} + +\item{verbose}{Logical \code{TRUE/FALSE}. Provides information about the flow of +information between the client and server.} + +\item{return_sf}{Logical \code{TRUE} or \code{FALSE}. +Should the function return an \code{\link[sf:sf]{sf}} spatial object? If \code{FALSE} +(the default value) it returns a \code{\link[tibble:tibble]{tibble}}. Note that +you need to have the \CRANpkg{sf} package installed.} + +\item{extract_metadata}{Logical \code{TRUE/FALSE}. On \code{TRUE} the output is +a \code{\link[tibble:tibble]{tibble}} with the description of the fields. See also +\code{\link[=get_metadata_aemet]{get_metadata_aemet()}}.} + +\item{progress}{Logical, display a \code{\link[cli:cli_progress_bar]{cli::cli_progress_bar()}} object. If +\code{verbose = TRUE} won't be displayed.} +} +\value{ +A \code{\link[tibble:tibble]{tibble}} or a \CRANpkg{sf} object. +} +\description{ +Get a database of daily weather forecasts for a beach. Beach database can +be accessed with \code{\link[=aemet_beaches]{aemet_beaches()}}. +} +\section{API Key}{ +You need to set your API Key globally using \code{\link[=aemet_api_key]{aemet_api_key()}}. +} + +\examples{ +\dontshow{if (aemet_detect_api_key()) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} +# Forecast for beaches in Palma, Mallorca +library(dplyr) +library(ggplot2) + +palma_b <- aemet_beaches() \%>\% + filter(ID_MUNICIPIO == "07040") + +forecast_b <- aemet_forecast_beaches(palma_b$ID_PLAYA) +glimpse(forecast_b) + +ggplot(forecast_b) + + geom_line(aes(fecha, tagua_valor1, color = nombre)) + + facet_wrap(~nombre, ncol = 1) + + labs( + title = "Water temperature in beaches of Palma (ES)", + subtitle = "Forecast 3-days", + x = "Date", + y = "Temperature (Celsius)", + color = "Beach" + ) +\dontshow{\}) # examplesIf} +} +\seealso{ +\code{\link[=aemet_beaches]{aemet_beaches()}} for municipality codes. + +Other aemet_api_data: +\code{\link{aemet_beaches}()}, +\code{\link{aemet_daily_clim}()}, +\code{\link{aemet_extremes_clim}()}, +\code{\link{aemet_forecast_daily}()}, +\code{\link{aemet_last_obs}()}, +\code{\link{aemet_monthly}}, +\code{\link{aemet_normal}}, +\code{\link{aemet_stations}()} + +Other forecasts: +\code{\link{aemet_forecast_daily}()}, +\code{\link{aemet_forecast_tidy}()} +} +\concept{aemet_api_data} +\concept{forecasts} diff --git a/man/aemet_forecast_utils.Rd b/man/aemet_forecast_utils.Rd index 94a6dc5d..855e776b 100644 --- a/man/aemet_forecast_utils.Rd +++ b/man/aemet_forecast_utils.Rd @@ -95,6 +95,7 @@ ggplot(temp_end) + } \seealso{ Other forecasts: +\code{\link{aemet_forecast_beaches}()}, \code{\link{aemet_forecast_daily}()} } \concept{forecasts} diff --git a/man/aemet_last_obs.Rd b/man/aemet_last_obs.Rd index 214cf012..ba7144b5 100644 --- a/man/aemet_last_obs.Rd +++ b/man/aemet_last_obs.Rd @@ -51,8 +51,10 @@ glimpse(obs) } \seealso{ Other aemet_api_data: +\code{\link{aemet_beaches}()}, \code{\link{aemet_daily_clim}()}, \code{\link{aemet_extremes_clim}()}, +\code{\link{aemet_forecast_beaches}()}, \code{\link{aemet_forecast_daily}()}, \code{\link{aemet_monthly}}, \code{\link{aemet_normal}}, diff --git a/man/aemet_monthly.Rd b/man/aemet_monthly.Rd index be9ec814..d0e040f8 100644 --- a/man/aemet_monthly.Rd +++ b/man/aemet_monthly.Rd @@ -82,8 +82,10 @@ glimpse(obs) } \seealso{ Other aemet_api_data: +\code{\link{aemet_beaches}()}, \code{\link{aemet_daily_clim}()}, \code{\link{aemet_extremes_clim}()}, +\code{\link{aemet_forecast_beaches}()}, \code{\link{aemet_forecast_daily}()}, \code{\link{aemet_last_obs}()}, \code{\link{aemet_normal}}, diff --git a/man/aemet_normal.Rd b/man/aemet_normal.Rd index 282e4af6..f436b936 100644 --- a/man/aemet_normal.Rd +++ b/man/aemet_normal.Rd @@ -64,8 +64,10 @@ glimpse(obs) } \seealso{ Other aemet_api_data: +\code{\link{aemet_beaches}()}, \code{\link{aemet_daily_clim}()}, \code{\link{aemet_extremes_clim}()}, +\code{\link{aemet_forecast_beaches}()}, \code{\link{aemet_forecast_daily}()}, \code{\link{aemet_last_obs}()}, \code{\link{aemet_monthly}}, diff --git a/man/aemet_stations.Rd b/man/aemet_stations.Rd index b2173d6b..3626d3b7 100644 --- a/man/aemet_stations.Rd +++ b/man/aemet_stations.Rd @@ -46,8 +46,10 @@ identical(stations, stations2) } \seealso{ Other aemet_api_data: +\code{\link{aemet_beaches}()}, \code{\link{aemet_daily_clim}()}, \code{\link{aemet_extremes_clim}()}, +\code{\link{aemet_forecast_beaches}()}, \code{\link{aemet_forecast_daily}()}, \code{\link{aemet_last_obs}()}, \code{\link{aemet_monthly}}, diff --git a/tests/testthat/_snaps/aemet_beaches.md b/tests/testthat/_snaps/aemet_beaches.md new file mode 100644 index 00000000..9641c953 --- /dev/null +++ b/tests/testthat/_snaps/aemet_beaches.md @@ -0,0 +1,16 @@ +# Errors and validations + + Code + aemet_beaches(return_sf = "A") + Condition + Error in `aemet_beaches()`: + ! is.logical(return_sf) is not TRUE + +--- + + Code + aemet_beaches(verbose = "A") + Condition + Error in `aemet_beaches()`: + ! is.logical(verbose) is not TRUE + diff --git a/tests/testthat/_snaps/aemet_forecast_beach.md b/tests/testthat/_snaps/aemet_forecast_beach.md new file mode 100644 index 00000000..ffe64db4 --- /dev/null +++ b/tests/testthat/_snaps/aemet_forecast_beach.md @@ -0,0 +1,12 @@ +# Online + + Code + alle <- aemet_forecast_beaches(c(st, "ASTRINGWHATEVER")) + Condition + Warning in `aemet_api_call()`: + HTTP 404: Error al obtener los datos + Message + + AEMET API call for 'ASTRINGWHATEVER' returned an error + Return NULL for this query + diff --git a/tests/testthat/test-aemet_beaches.R b/tests/testthat/test-aemet_beaches.R new file mode 100644 index 00000000..150d2369 --- /dev/null +++ b/tests/testthat/test-aemet_beaches.R @@ -0,0 +1,38 @@ +test_that("Errors and validations", { + # Validations + expect_snapshot(aemet_beaches(return_sf = "A"), error = TRUE) + expect_snapshot(aemet_beaches(verbose = "A"), error = TRUE) +}) + + +test_that("Online", { + skip_on_cran() + skip_if_offline() + skip_if_not(aemet_detect_api_key(), message = "No API KEY") + + # First clean cache + cached_df <- file.path(tempdir(), "aemet_beaches.rds") + cached_date <- file.path(tempdir(), "aemet_beaches_date.rds") + unlink(cached_df) + unlink(cached_date) + + # First download + s <- aemet_beaches() + + + # Now is cached + expect_message( + aemet_beaches(verbose = TRUE), + regexp = "Loading beaches from temporal cached file" + ) + + st1 <- aemet_beaches() + expect_s3_class(st1, "tbl_df") + + # sf + Sys.sleep(0.5) + alll_sf <- aemet_beaches(return_sf = TRUE) + + expect_s3_class(alll_sf, "sf") + expect_true(unique(sf::st_geometry_type(alll_sf)) == "POINT") +}) diff --git a/tests/testthat/test-aemet_forecast_beach.R b/tests/testthat/test-aemet_forecast_beach.R new file mode 100644 index 00000000..1dafbbb0 --- /dev/null +++ b/tests/testthat/test-aemet_forecast_beach.R @@ -0,0 +1,35 @@ +test_that("Online", { + skip_on_cran() + skip_if_offline() + skip_if_not(aemet_detect_api_key(), message = "No API KEY") + + bc <- aemet_beaches() + st <- bc$ID_PLAYA[1:3] + meta <- aemet_forecast_beaches(st, extract_metadata = TRUE) + # Same as + meta2 <- aemet_forecast_beaches("NOEXIST", extract_metadata = TRUE) + expect_identical(meta, meta2) + + # Default + expect_message(alll <- aemet_forecast_beaches(st, verbose = TRUE)) + expect_s3_class(alll, "tbl_df") + + expect_identical(unique(alll$id), st) + + # Same as + alln <- aemet_forecast_beaches(as.numeric(st)) + expect_identical(alln, alll) + + # Throw error + expect_snapshot(alle <- aemet_forecast_beaches(c(st, "ASTRINGWHATEVER"))) + + expect_identical(alle, alll) + + + # sf + Sys.sleep(0.5) + alll_sf <- aemet_forecast_beaches(st, return_sf = TRUE) + + expect_s3_class(alll_sf, "sf") + expect_true(unique(sf::st_geometry_type(alll_sf)) == "POINT") +}) diff --git a/vignettes/articles/interpolation.Rmd b/vignettes/articles/interpolation.Rmd index 3d7ff47e..041467b4 100644 --- a/vignettes/articles/interpolation.Rmd +++ b/vignettes/articles/interpolation.Rmd @@ -55,7 +55,7 @@ Filomena](https://en.wikipedia.org/wiki/Storm_Filomena) brought unusual heavy snowfall to parts of Spain, with Madrid recording its heaviest snowfall since 1971. We should be able to spot that. -```{r climatic_data} +```{r climatic_data, cache=TRUE} clim_data <- aemet_daily_clim( start = "2020-12-21", end = "2021-03-20", diff --git a/vignettes/climaemet.Rmd b/vignettes/climaemet.Rmd index af0c5a2a..f00d0d9c 100644 --- a/vignettes/climaemet.Rmd +++ b/vignettes/climaemet.Rmd @@ -87,24 +87,24 @@ See how a `tibble` is displayed: # See a tibble in action aemet_last_obs("9434") -#> # A tibble: 12 × 25 -#> idema lon fint prec alt vmax vv dv lat dmax -#> -#> 1 9434 -1.00 2024-06-21 21:00:00 0 249 3.5 2.1 321 41.7 330 -#> 2 9434 -1.00 2024-06-21 22:00:00 0 249 4.6 3.6 264 41.7 263 -#> 3 9434 -1.00 2024-06-21 23:00:00 0 249 4.1 3 257 41.7 270 -#> 4 9434 -1.00 2024-06-22 00:00:00 0 249 4.7 2.3 262 41.7 288 -#> 5 9434 -1.00 2024-06-22 01:00:00 0 249 4.3 2.6 315 41.7 240 -#> 6 9434 -1.00 2024-06-22 02:00:00 0 249 6.2 5 292 41.7 298 -#> 7 9434 -1.00 2024-06-22 03:00:00 0 249 6.8 4.4 296 41.7 288 -#> 8 9434 -1.00 2024-06-22 04:00:00 0 249 5.5 3.5 305 41.7 293 -#> 9 9434 -1.00 2024-06-22 05:00:00 0 249 5.6 2.5 302 41.7 310 -#> 10 9434 -1.00 2024-06-22 06:00:00 0 249 5.5 4.3 312 41.7 315 -#> 11 9434 -1.00 2024-06-22 07:00:00 0 249 7.2 4.9 302 41.7 303 -#> 12 9434 -1.00 2024-06-22 08:00:00 0 249 8.1 6.1 297 41.7 293 -#> # ℹ 15 more variables: ubi , pres , hr , stdvv , ts , -#> # pres_nmar , tamin , ta , tamax , tpr , -#> # stddv , inso , tss5cm , pacutp , tss20cm +#> # A tibble: 13 × 25 +#> idema lon fint prec alt vmax vv dv lat dmax ubi pres hr +#> +#> 1 9434 -1.00 2024-06-22 21:00:00 0 249 9.7 6.3 323 41.7 333 ZARAGOZA… 992 56 +#> 2 9434 -1.00 2024-06-22 22:00:00 0 249 10.5 6.9 302 41.7 310 ZARAGOZA… 992. 57 +#> 3 9434 -1.00 2024-06-22 23:00:00 0 249 10.5 5.8 305 41.7 308 ZARAGOZA… 992. 60 +#> 4 9434 -1.00 2024-06-23 00:00:00 0 249 11 8.4 305 41.7 318 ZARAGOZA… 991. 60 +#> 5 9434 -1.00 2024-06-23 01:00:00 0 249 11.8 8.5 296 41.7 290 ZARAGOZA… 991. 62 +#> 6 9434 -1.00 2024-06-23 02:00:00 0 249 12.2 8 304 41.7 298 ZARAGOZA… 990. 62 +#> 7 9434 -1.00 2024-06-23 03:00:00 0 249 12.6 9.3 301 41.7 305 ZARAGOZA… 990. 65 +#> 8 9434 -1.00 2024-06-23 04:00:00 0 249 13.2 10.1 302 41.7 303 ZARAGOZA… 989. 66 +#> 9 9434 -1.00 2024-06-23 05:00:00 0 249 12.5 7.4 292 41.7 305 ZARAGOZA… 989. 69 +#> 10 9434 -1.00 2024-06-23 06:00:00 0 249 15.5 11.5 297 41.7 298 ZARAGOZA… 989. 66 +#> 11 9434 -1.00 2024-06-23 07:00:00 0 249 15.4 11.7 305 41.7 303 ZARAGOZA… 989 64 +#> 12 9434 -1.00 2024-06-23 08:00:00 0 249 16.1 10.5 312 41.7 308 ZARAGOZA… 988. 60 +#> 13 9434 -1.00 2024-06-23 09:00:00 0 249 16.3 10.7 315 41.7 310 ZARAGOZA… 988. 57 +#> # ℹ 12 more variables: stdvv , ts , pres_nmar , tamin , ta , +#> # tamax , tpr , stddv , inso , tss5cm , pacutp , tss20cm ``` Note that when possible, data representing dates and numbers are converted to diff --git a/vignettes/example-gif.gif b/vignettes/example-gif.gif index 05156d3b..0fb53440 100644 Binary files a/vignettes/example-gif.gif and b/vignettes/example-gif.gif differ diff --git a/vignettes/extending-climaemet.Rmd b/vignettes/extending-climaemet.Rmd index 0ce1576b..0f6e0069 100644 --- a/vignettes/extending-climaemet.Rmd +++ b/vignettes/extending-climaemet.Rmd @@ -171,278 +171,3 @@ knitr::include_graphics(giffile) Example: Surface analysis map provided by AEMET

Example: Surface analysis map provided by AEMET

- -## Example: Beach forecast - -This example is more elaborated, since the user would need to process the -results provided by the AEMET API. - -In first place we need to get the database of beaches: - - -``` r -library(readr) -library(tidyr) -library(dplyr) - -db_beach <- read_csv2("https://www.aemet.es/documentos/es/eltiempo/prediccion/playas/Playas_codigos.csv", - show_col_types = FALSE, - locale = locale(encoding = "ISO-8859-1"), - trim_ws = TRUE -) -#> ℹ Using "','" as decimal and "'.'" as grouping mark. Use `read_delim()` for more control. -``` - -``` r - -db_beach -#> # A tibble: 591 × 8 -#> ID_PLAYA NOMBRE_PLAYA ID_PROVINCIA NOMBRE_PROVINCIA ID_MUNICIPIO -#> -#> 1 0301101 Raco de l'Albir 03 Alacant/Alicante 03011 -#> 2 0301401 Sant Joan / San Juan 03 Alacant/Alicante 03014 -#> 3 0301408 El Postiguet 03 Alacant/Alicante 03014 -#> 4 0301410 Saladar 03 Alacant/Alicante 03014 -#> 5 0301808 La Roda 03 Alacant/Alicante 03018 -#> 6 0301809 Cap Blanch 03 Alacant/Alicante 03018 -#> 7 0303102 Llevant / Playa de Levan… 03 Alacant/Alicante 03031 -#> 8 0303104 Ponent / Playa de Ponien… 03 Alacant/Alicante 03031 -#> 9 0304105 Cala Fustera 03 Alacant/Alicante 03041 -#> 10 0304704 La Fossa 03 Alacant/Alicante 03047 -#> # ℹ 581 more rows -#> # ℹ 3 more variables: NOMBRE_MUNICIPIO , LATITUD , LONGITUD -``` - -Next, we can check the response of the API for a specific case: - - -``` r -# Heliopolis, Benicassim - -id_beach <- "1202805" - -api_entry <- "/api/prediccion/especifica/playa/" - -api_call <- paste0(api_entry, id_beach) - -# And we make the call - -beach_api <- get_data_aemet(api_call) - -glimpse(beach_api) -#> Rows: 1 -#> Columns: 6 -#> $ origen -#> $ elaborado "2024-06-22T08:00:25" -#> $ nombre "Heliopolis" -#> $ localidad 12028 -#> $ prediccion -#> $ id 1202805 -``` - -The response needs further treatment, the forecast is in the `prediccion` column -as a data set. We can have first a look: - - -``` r -glimpse(beach_api$prediccion$dia[[1]]) -#> Rows: 3 -#> Columns: 11 -#> $ estadoCielo -#> $ viento -#> $ oleaje -#> $ tMaxima -#> $ sTermica -#> $ tAgua -#> $ uvMax -#> $ fecha 20240622, 20240623, 20240624 -#> $ tmaxima -#> $ stermica -#> $ tagua -``` - -We need then to un-nest the data frame of forecast, and perform a few additional -conversions of `Date` columns: - - -``` r -for_pred <- beach_api$prediccion$dia[[1]] - -# Need cols now - -coln <- names(for_pred) - - -for_pred_2 <- unnest(for_pred, names_sep = "_", cols = all_of(coln)) %>% - mutate(fecha = as.Date(as.character(fecha), - tryFormats = c("%Y-%m-%d", "%Y/%m/%d", "%Y%m%d") - )) %>% - # We add interesting info of the metadata - mutate( - id_beach = beach_api$id, - elaborado = lubridate::as_datetime(beach_api$elaborado) - ) %>% - relocate(id_beach, elaborado, fecha) - -glimpse(for_pred_2) -#> Rows: 3 -#> Columns: 34 -#> $ id_beach 1202805, 1202805, 1202805 -#> $ elaborado 2024-06-22 08:00:25, 2024-06-22 08:00:25, 202… -#> $ fecha 2024-06-22, 2024-06-23, 2024-06-24 -#> $ estadoCielo_value "", "", "" -#> $ estadoCielo_f1 100, 100, 110 -#> $ estadoCielo_descripcion1 "despejado", "despejado", "nuboso" -#> $ estadoCielo_f2 110, 100, 110 -#> $ estadoCielo_descripcion2 "nuboso", "despejado", "nuboso" -#> $ viento_value "", "", "" -#> $ viento_f1 210, 210, 210 -#> $ viento_descripcion1 "flojo", "flojo", "flojo" -#> $ viento_f2 210, 210, 210 -#> $ viento_descripcion2 "flojo", "flojo", "flojo" -#> $ oleaje_value "", "", "" -#> $ oleaje_f1 310, 310, 310 -#> $ oleaje_descripcion1 "débil", "débil", "débil" -#> $ oleaje_f2 310, 310, 310 -#> $ oleaje_descripcion2 "débil", "débil", "débil" -#> $ tMaxima_value "", "", "" -#> $ tMaxima_valor1 29, 29, 27 -#> $ sTermica_value "", "", "" -#> $ sTermica_valor1 460, 460, 460 -#> $ sTermica_descripcion1 "calor agradable", "calor agradable", "calor… -#> $ tAgua_value "", "", "" -#> $ tAgua_valor1 23, 23, 23 -#> $ uvMax_value "", "", "" -#> $ uvMax_valor1 8, 9, 8 -#> $ tmaxima_value "", "", "" -#> $ tmaxima_valor1 29, 29, 27 -#> $ stermica_value "", "", "" -#> $ stermica_valor1 460, 460, 460 -#> $ stermica_descripcion1 "calor agradable", "calor agradable", "calor… -#> $ tagua_value "", "", "" -#> $ tagua_valor1 23, 23, 23 -``` - -Once that we have the helper, we can wrap everything to provide a full-fledged -function: - - -``` r -# Wrap on a function -aemet_usr__forecast_beach <- function(id_beach = NULL) { - api_entry <- "/api/prediccion/especifica/playa/" - api_call <- paste0(api_entry, id_beach) - - beach_api <- get_data_aemet(api_call) - for_pred <- beach_api$prediccion$dia[[1]] - - # Need cols now - - coln <- names(for_pred) - - - for_pred_2 <- unnest(for_pred, names_sep = "_", cols = all_of(coln)) %>% - mutate(fecha = as.Date(as.character(fecha), - tryFormats = c("%Y-%m-%d", "%Y/%m/%d", "%Y%m%d") - )) %>% - # We add interesting info of the metadata - mutate( - id_beach = beach_api$id, - elaborado = lubridate::as_datetime(beach_api$elaborado) - ) %>% - relocate(id_beach, elaborado, fecha) - - for_pred_2 -} -``` - -Here we go! We already have our function. We can try it now: - - -``` r -aemet_usr__forecast_beach("0301401") %>% - glimpse() -#> Rows: 3 -#> Columns: 34 -#> $ id_beach 301401, 301401, 301401 -#> $ elaborado 2024-06-22 08:00:25, 2024-06-22 08:00:25, 202… -#> $ fecha 2024-06-22, 2024-06-23, 2024-06-24 -#> $ estadoCielo_value "", "", "" -#> $ estadoCielo_f1 100, 120, 110 -#> $ estadoCielo_descripcion1 "despejado", "muy nuboso", "nuboso" -#> $ estadoCielo_f2 100, 100, 100 -#> $ estadoCielo_descripcion2 "despejado", "despejado", "despejado" -#> $ viento_value "", "", "" -#> $ viento_f1 210, 210, 210 -#> $ viento_descripcion1 "flojo", "flojo", "flojo" -#> $ viento_f2 210, 220, 210 -#> $ viento_descripcion2 "flojo", "moderado", "flojo" -#> $ oleaje_value "", "", "" -#> $ oleaje_f1 310, 310, 320 -#> $ oleaje_descripcion1 "débil", "débil", "moderado" -#> $ oleaje_f2 310, 320, 320 -#> $ oleaje_descripcion2 "débil", "moderado", "moderado" -#> $ tMaxima_value "", "", "" -#> $ tMaxima_valor1 28, 27, 27 -#> $ sTermica_value "", "", "" -#> $ sTermica_valor1 460, 460, 460 -#> $ sTermica_descripcion1 "calor agradable", "calor agradable", "calor… -#> $ tAgua_value "", "", "" -#> $ tAgua_valor1 23, 23, 24 -#> $ uvMax_value "", "", "" -#> $ uvMax_valor1 9, 9, 9 -#> $ tmaxima_value "", "", "" -#> $ tmaxima_valor1 28, 27, 27 -#> $ stermica_value "", "", "" -#> $ stermica_valor1 460, 460, 460 -#> $ stermica_descripcion1 "calor agradable", "calor agradable", "calor… -#> $ tagua_value "", "", "" -#> $ tagua_valor1 23, 23, 24 -``` - -``` r - - -# Several using apply and bind_rows -several <- db_beach$ID_PLAYA[7:10] %>% - lapply(aemet_usr__forecast_beach) %>% - bind_rows() - -glimpse(several) -#> Rows: 12 -#> Columns: 34 -#> $ id_beach 303102, 303102, 303102, 303104, 303104, 30310… -#> $ elaborado 2024-06-22 08:00:25, 2024-06-22 08:00:25, 20… -#> $ fecha 2024-06-22, 2024-06-23, 2024-06-24, 2024-06-… -#> $ estadoCielo_value "", "", "", "", "", "", "", "", "", "", "", "" -#> $ estadoCielo_f1 100, 120, 110, 100, 120, 110, 100, 120, 120, … -#> $ estadoCielo_descripcion1 "despejado", "muy nuboso", "nuboso", "despeja… -#> $ estadoCielo_f2 100, 100, 110, 100, 100, 110, 100, 100, 100, … -#> $ estadoCielo_descripcion2 "despejado", "despejado", "nuboso", "despejad… -#> $ viento_value "", "", "", "", "", "", "", "", "", "", "", "" -#> $ viento_f1 210, 220, 210, 210, 220, 210, 210, 210, 210, … -#> $ viento_descripcion1 "flojo", "moderado", "flojo", "flojo", "moder… -#> $ viento_f2 210, 220, 210, 210, 220, 210, 220, 220, 220, … -#> $ viento_descripcion2 "flojo", "moderado", "flojo", "flojo", "moder… -#> $ oleaje_value "", "", "", "", "", "", "", "", "", "", "", "" -#> $ oleaje_f1 310, 310, 310, 310, 310, 320, 310, 310, 320, … -#> $ oleaje_descripcion1 "débil", "débil", "débil", "débil", "débil", … -#> $ oleaje_f2 310, 310, 320, 310, 310, 320, 310, 320, 320, … -#> $ oleaje_descripcion2 "débil", "débil", "moderado", "débil", "débil… -#> $ tMaxima_value "", "", "", "", "", "", "", "", "", "", "", "" -#> $ tMaxima_valor1 27, 27, 25, 27, 27, 25, 28, 29, 27, 28, 29, 27 -#> $ sTermica_value "", "", "", "", "", "", "", "", "", "", "", "" -#> $ sTermica_valor1 460, 460, 460, 460, 460, 460, 460, 460, 460, … -#> $ sTermica_descripcion1 "calor agradable", "calor agradable", "calor … -#> $ tAgua_value "", "", "", "", "", "", "", "", "", "", "", "" -#> $ tAgua_valor1 23, 23, 24, 23, 24, 24, 24, 25, 24, 24, 25, 24 -#> $ uvMax_value "", "", "", "", "", "", "", "", "", "", "", "" -#> $ uvMax_valor1 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 -#> $ tmaxima_value "", "", "", "", "", "", "", "", "", "", "", "" -#> $ tmaxima_valor1 27, 27, 25, 27, 27, 25, 28, 29, 27, 28, 29, 27 -#> $ stermica_value "", "", "", "", "", "", "", "", "", "", "", "" -#> $ stermica_valor1 460, 460, 460, 460, 460, 460, 460, 460, 460, … -#> $ stermica_descripcion1 "calor agradable", "calor agradable", "calor … -#> $ tagua_value "", "", "", "", "", "", "", "", "", "", "", "" -#> $ tagua_valor1 23, 23, 24, 23, 24, 24, 24, 25, 24, 24, 25, 24 -``` diff --git a/vignettes/extending-climaemet.Rmd.orig b/vignettes/extending-climaemet.Rmd.orig index 866f390c..7cb1ab01 100644 --- a/vignettes/extending-climaemet.Rmd.orig +++ b/vignettes/extending-climaemet.Rmd.orig @@ -91,126 +91,3 @@ writeBin(the_map, giffile) knitr::include_graphics(giffile) ``` - -## Example: Beach forecast - -This example is more elaborated, since the user would need to process the -results provided by the AEMET API. - -In first place we need to get the database of beaches: - -```{r getbeaches} - -library(readr) -library(tidyr) -library(dplyr) - -db_beach <- read_csv2("https://www.aemet.es/documentos/es/eltiempo/prediccion/playas/Playas_codigos.csv", - show_col_types = FALSE, - locale = locale(encoding = "ISO-8859-1"), - trim_ws = TRUE) - -db_beach - -``` - -Next, we can check the response of the API for a specific case: - -```{r checkb} - -# Heliopolis, Benicassim - -id_beach <- "1202805" - -api_entry <- "/api/prediccion/especifica/playa/" - -api_call <- paste0(api_entry, id_beach) - -# And we make the call - -beach_api <- get_data_aemet(api_call) - -glimpse(beach_api) - -``` - -The response needs further treatment, the forecast is in the `prediccion` column -as a data set. We can have first a look: - -```{r} - -glimpse(beach_api$prediccion$dia[[1]]) - -``` - -We need then to un-nest the data frame of forecast, and perform a few additional -conversions of `Date` columns: - -```{r} - -for_pred <- beach_api$prediccion$dia[[1]] - -# Need cols now - -coln <- names(for_pred) - - -for_pred_2 <- unnest(for_pred, names_sep = "_", cols = all_of(coln)) %>% - mutate(fecha = as.Date(as.character(fecha), - tryFormats = c("%Y-%m-%d", "%Y/%m/%d", "%Y%m%d"))) %>% - # We add interesting info of the metadata - mutate(id_beach = beach_api$id, - elaborado = lubridate::as_datetime(beach_api$elaborado)) %>% - relocate(id_beach, elaborado, fecha) - -glimpse(for_pred_2) - - -``` - -Once that we have the helper, we can wrap everything to provide a full-fledged -function: - -```{r} - -# Wrap on a function -aemet_usr__forecast_beach <- function(id_beach = NULL){ - api_entry <- "/api/prediccion/especifica/playa/" - api_call <- paste0(api_entry, id_beach) - - beach_api <- get_data_aemet(api_call) - for_pred <- beach_api$prediccion$dia[[1]] - -# Need cols now - -coln <- names(for_pred) - - -for_pred_2 <- unnest(for_pred, names_sep = "_", cols = all_of(coln)) %>% - mutate(fecha = as.Date(as.character(fecha), - tryFormats = c("%Y-%m-%d", "%Y/%m/%d", "%Y%m%d"))) %>% - # We add interesting info of the metadata - mutate(id_beach = beach_api$id, - elaborado = lubridate::as_datetime(beach_api$elaborado)) %>% - relocate(id_beach, elaborado, fecha) - -for_pred_2 -} -``` - -Here we go! We already have our function. We can try it now: - -```{r trynow} - -aemet_usr__forecast_beach("0301401") %>% - glimpse() - - -# Several using apply and bind_rows -several <- db_beach$ID_PLAYA[7:10] %>% - lapply(aemet_usr__forecast_beach) %>% - bind_rows() - -glimpse(several) - -```