diff --git a/.Rbuildignore b/.Rbuildignore
index cde4010e..7dfcc805 100644
--- a/.Rbuildignore
+++ b/.Rbuildignore
@@ -4,18 +4,18 @@
^\.Rproj\.user$
^\.rstudio$
^_pkgdown\.yml$
+^doc$
^docker$
^CHANGELOG\.md$
+^codecov.yml$
^data-raw$
^datasets/
^deploy\.sh$
-^docs$
+^Meta$
^NEWS\.md$
^README\.Rmd$
^reports$
^rrricanes\.code-workspace
-^doc$
-^Meta$
^vignettes/accumulated_cyclone_energy.Rmd$
^vignettes/forecast_advisory.Rmd$
^vignettes/probabilistic_storm_surge.Rmd$
diff --git a/.gitignore b/.gitignore
index ead3bb16..d2a68605 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,6 +7,6 @@ datasets
inst/doc
rrricanes.code-workspace
rrricanes.Rcheck
-rrricanes.wiki/
doc
+docs
Meta
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e81148e0..051a3593 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -14,16 +14,22 @@ project adheres to [Semantic Versioning](http://semver.org/).
- `get_storm_list` returns dataframe of all known cyclones. (#114)
### Changed
- - `gis_download` and `gis_latest` can accept parameters for rgdal::readOGR
- (#104).
+ - `gis_latest` can accept parameters for rgdal::readOGR (#104).
+ - `gis_download` modified to download zip files and extract contents
+ returning a vector of files within the zip.
+
- `ep_prblty_stations` now returns all stations.
- `al_prblty_stations`, `cp_prblty_stations` and `ep_prblty_stations`
datasets were modified with additional columns. Changes are documented.
### Removed
- - NA
+ - `tracking_chart`, `al_tracking_chart`, and `ep_tracking_chart` all removed
+ in favor of using `rnaturalearth` and associated data packages, or other
+ mapping packages.
+
+ - `shp_to_df` removed; users can use `sf::st_read`
### Deprecated
- NA
diff --git a/DESCRIPTION b/DESCRIPTION
index 3b71c2ac..269863a9 100644
--- a/DESCRIPTION
+++ b/DESCRIPTION
@@ -42,10 +42,15 @@ Imports:
Suggests:
covr,
devtools,
+ gganimate,
+ HURDAT,
knitr,
+ magick,
rmarkdown,
+ rnaturalearthhires,
+ rrricanesdata,
+ scales,
sf,
- sp,
testthat
RoxygenNote: 6.1.1
VignetteBuilder: knitr
diff --git a/NAMESPACE b/NAMESPACE
index 192ac9ed..fd0ec5a2 100644
--- a/NAMESPACE
+++ b/NAMESPACE
@@ -1,10 +1,8 @@
# Generated by roxygen2: do not edit by hand
export(al_prblty_stations)
-export(al_tracking_chart)
export(cp_prblty_stations)
export(ep_prblty_stations)
-export(ep_tracking_chart)
export(get_discus)
export(get_fstadv)
export(get_ftp_storm_data)
@@ -29,14 +27,12 @@ export(knots_to_mph)
export(mb_to_in)
export(nm_to_sm)
export(saffir)
-export(shp_to_df)
export(status_abbr_to_str)
export(tidy_adv)
export(tidy_fcst)
export(tidy_fcst_wr)
export(tidy_fstadv)
export(tidy_wr)
-export(tracking_chart)
export(twoal)
export(twoep)
importFrom(magrittr,"%>%")
diff --git a/NEWS.md b/NEWS.md
index eb64e3ed..05ca3939 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -14,14 +14,19 @@ rrricanes Unreleased (yyyy-mm-dd)
* Allow parameters for rgdal::readOGR (#104)
-* Add `tidy_adv` to replace `tidy_fstadv`; `tidy_fstadv` will be removed in
- release 0.2.2 (#103)
+* Add `tidy_adv` to replace `tidy_fstadv`; `tidy_fstadv` will be removed in release 0.2.2 (#103)
* `al_prblty_stations` and `cp_prblty_stations` updated
to accomodate new dataset. (#46)
* `ep_prblty_stations` now returns dataset of east Pacific stations. (#46)
+* `tracking_chart` and associated functions have been removed in favor of rnaturalearth and related packages. See `vignette("gis_data", package = "rrricanes") for details.
+
+* `gis_download` no longer reads in the shapefiles; only downloads and extracts the zip files.
+
+* `shp_to_df` also removed in favor of built-in `sf` and `ggplot2` functions.
+
### BUG FIXES
* `tidy_fcst` only returned forecasts for hours 12:96. Now returns 120. (#107)
diff --git a/R/base.R b/R/base.R
index d69af7d7..4035f7fa 100755
--- a/R/base.R
+++ b/R/base.R
@@ -54,9 +54,7 @@
#' To install \code{rrricanesdata}, run
#'
#' \code{
-#' install.packages("rrricanesdata",
-#' repos = "https://timtrice.github.io/drat/",
-#' type = "source")
+#' remotes::install_github("ropensci/rrricanesdata")
#' }
#'
#' See \code{vignette("installing_rrricanesdata", package = "rrricanes")} for
@@ -83,11 +81,6 @@
#' \code{\link{gis_download}} will download the datasets from the above
#' functions.
#'
-#' Some GIS datasets will need to be converted to dataframes to plot geoms. Use
-#' \code{\link{shp_to_df}} to convert SpatialLinesDataFrames and
-#' SpatialPolygonsDataFrames. SpatialPointsDataFrames can be converted using
-#' \code{tibble::as_data_frame} targeting the @data object.
-#'
#' @section Package Options:
#'
#' \code{dplyr.show_progress} displays the dplyr progress bar when scraping raw
@@ -141,13 +134,15 @@ hasData <- function(has_data = .pkgenv$has_data) {
}
}
-utils::globalVariables(c("Date", "Hour", "Minute", "Lat", "LatHemi", "Lon",
- "LonHemi", "Wind", "Gust", "Month", "Year", "FcstDate",
- "WindField34", "WindField50", "WindField64", "lat",
- "long", "group", ".", "NW34", "name", "data", "Basin",
- stringr::str_c(c("NE", "SE", "SW", "NW", "64")),
- stringr::str_c(c("NE", "SE", "SW", "NW", "50")),
- stringr::str_c(c("NE", "SE", "SW", "NW", "34"))))
+utils::globalVariables(c(
+ "Date", "Hour", "Minute", "Lat", "LatHemi", "Lon",
+ "LonHemi", "Wind", "Gust", "Month", "Year", "FcstDate",
+ "WindField34", "WindField50", "WindField64", "lat",
+ "long", "group", ".", "NW34", "name", "data", "Basin",
+ stringr::str_c(c("NE", "SE", "SW", "NW", "64")),
+ stringr::str_c(c("NE", "SE", "SW", "NW", "50")),
+ stringr::str_c(c("NE", "SE", "SW", "NW", "34"))
+))
#' @title extract_year_archive_link
#' @description Extracts the year from the archive link.
@@ -156,7 +151,7 @@ utils::globalVariables(c("Date", "Hour", "Minute", "Lat", "LatHemi", "Lon",
#' @keywords internal
extract_year_archive_link <- function(link) {
# Year is listed in link towards the end surrounded by slashes.
- as.numeric(stringr::str_match(link, '/([:digit:]{4})/')[,2])
+ as.numeric(stringr::str_match(link, "/([:digit:]{4})/")[, 2])
}
#' @title get_url_contents
@@ -167,7 +162,6 @@ extract_year_archive_link <- function(link) {
#' @param link URL to download
#' @keywords internal
get_url_contents <- function(links) {
-
download_text <- function(grouped_links) {
# Create a new Async object with `grouped_links`
@@ -177,21 +171,24 @@ get_url_contents <- function(links) {
results <- grouped_links$get()
# Do we have any bad `grouped_links`?
- bad_results_ind <- which(purrr::map(results, ~.$success()) == FALSE)
+ bad_results_ind <- which(purrr::map(results, ~ .$success()) == FALSE)
if (length(bad_results_ind) > 0) {
- warning(sprintf("URL %s was unsuccesful.\n",
- purrr::map(results[bad_results_ind], ~.$url)),
- call. = FALSE)
+ warning(sprintf(
+ "URL %s was unsuccesful.\n",
+ purrr::map(results[bad_results_ind], ~ .$url)
+ ),
+ call. = FALSE
+ )
# Remove bad `grouped_links`
results <- results[-bad_results_ind]
}
- purrr::map_chr(results, ~.$parse("UTF-8"))
+ purrr::map_chr(results, ~ .$parse("UTF-8"))
}
# Create groups of links divisible by 80. We are to allow no more than 80
# requests every 10 seconds. If length of `link` is less than 80, then will
# only have one group and should have no delay.
- groups <- ceiling(seq_along(1:length(links))/80)
+ groups <- ceiling(seq_along(1:length(links)) / 80)
links <- split(links, groups)
# Set progress bar
@@ -200,14 +197,14 @@ get_url_contents <- function(links) {
contents <-
links %>%
purrr::imap(.f = function(x, y) {
-
if (as.numeric(y) != length(links)) {
# Send group of links to `download_txt`
txt <- download_text(x)
# We are not in the last group; apply a delay
p$tick()$print()
- if (getOption("rrricanes.working_msg"))
+ if (getOption("rrricanes.working_msg")) {
message("Waiting 10 seconds to retrieve large numbers of links.")
+ }
p$pause(10)
txt
} else {
@@ -218,7 +215,6 @@ get_url_contents <- function(links) {
})
purrr::flatten_chr(contents)
-
}
#' @title get_nhc_link
@@ -228,8 +224,9 @@ get_url_contents <- function(links) {
#' @param protocol https or http
#' @keywords internal
get_nhc_link <- function(withTrailingSlash = TRUE, protocol = "https") {
- if (withTrailingSlash)
+ if (withTrailingSlash) {
return(sprintf("%s://www.nhc.noaa.gov/", protocol))
+ }
sprintf("%s://www.nhc.noaa.gov", protocol)
}
@@ -238,8 +235,9 @@ get_nhc_link <- function(withTrailingSlash = TRUE, protocol = "https") {
#' @inheritParams get_nhc_link
#' @keywords internal
get_nhc_ftp_link <- function(withTrailingSlash = TRUE) {
- if (withTrailingSlash)
+ if (withTrailingSlash) {
return("ftp://ftp.nhc.noaa.gov/")
+ }
"ftp://ftp.nhc.noaa.gov"
}
@@ -272,8 +270,9 @@ mb_to_in <- function(x) {
#' @keywords internal
month_str_to_num <- function(m) {
abbr <- which(month.abb == stringr::str_to_title(m))
- if (purrr::is_empty(abbr))
+ if (purrr::is_empty(abbr)) {
stop(sprintf("%s is not a valid month abbreviation.", m))
+ }
abbr
}
diff --git a/R/discus.R b/R/discus.R
index 30a72675..02500649 100644
--- a/R/discus.R
+++ b/R/discus.R
@@ -30,7 +30,6 @@ get_discus <- function(links) {
#' @seealso \code{\link{get_discus}}
#' @keywords internal
discus <- function(contents) {
-
status <- scrape_header(
contents = contents,
# The "SPECIAL" pattern has to be left here; moving it under
@@ -43,12 +42,11 @@ discus <- function(contents) {
key <- scrape_key(contents)
tibble::tibble(
- Status = status[,1],
- Name = status[,2],
- Adv = as.numeric(status[,3]),
+ Status = status[, 1],
+ Name = status[, 2],
+ Adv = as.numeric(status[, 3]),
Date = issue_date,
Key = key,
Contents = contents
)
-
}
diff --git a/R/filters.R b/R/filters.R
index 9b65d1f5..e3f13098 100644
--- a/R/filters.R
+++ b/R/filters.R
@@ -41,8 +41,9 @@ filter_posest <- function(links) {
#' @keywords internal
filter_public <- function(links) {
grep("/pub/P(AL|EP)|/pub/PA(AL|EP)|/pub/PB(AL|EP)|public",
- x = links,
- value = TRUE)
+ x = links,
+ value = TRUE
+ )
}
#' @title filter_prblty
diff --git a/R/fstadv.R b/R/fstadv.R
index 6c319a14..e6581693 100644
--- a/R/fstadv.R
+++ b/R/fstadv.R
@@ -89,7 +89,6 @@ get_fstadv <- function(links) {
#' @param contents URL of a specific FORECAST/ADVISORY product
#' @keywords internal
fstadv <- function(contents) {
-
status <- scrape_header(
contents = contents,
# The "SPECIAL" pattern has to be left here; moving it under
@@ -108,29 +107,28 @@ fstadv <- function(contents) {
wind_radius <- fstadv_wind_radius(contents)
prev_pos <- fstadv_prev_pos(contents, issue_date)
seas <- fstadv_seas(contents)
- forecasts <- fstadv_forecasts(contents, key, status[,3], issue_date)
+ forecasts <- fstadv_forecasts(contents, key, status[, 3], issue_date)
tibble::tibble(
- Status = status[,1],
- Name = status[,2],
- Adv = as.numeric(status[,3]),
+ Status = status[, 1],
+ Name = status[, 2],
+ Adv = as.numeric(status[, 3]),
Date = issue_date,
Key = key,
- Lat = lat_lon[,1],
- Lon = lat_lon[,2],
- Wind = winds_gusts[,1],
- Gust = winds_gusts[,2],
+ Lat = lat_lon[, 1],
+ Lon = lat_lon[, 2],
+ Wind = winds_gusts[, 1],
+ Gust = winds_gusts[, 2],
Pressure = pressure,
PosAcc = posacc,
- FwdDir = fwd_mvmt[,1],
- FwdSpeed = fwd_mvmt[,2],
+ FwdDir = fwd_mvmt[, 1],
+ FwdSpeed = fwd_mvmt[, 2],
Eye = eye,
Seas = seas,
WindRadius = wind_radius,
Forecast = forecasts
) %>%
tidyr::unnest()
-
}
#' @title fstadv_eye
@@ -139,10 +137,12 @@ fstadv <- function(contents) {
#' @return numeric
#' @keywords internal
fstadv_eye <- function(contents) {
- ptn <- stringr::str_c('EYE DIAMETER[ ]+',
- '([0-9]{2,3})', # Eye diameter, integer
- '[ ]+NM')
- as.numeric(stringr::str_match(contents, ptn)[,2])
+ ptn <- stringr::str_c(
+ "EYE DIAMETER[ ]+",
+ "([0-9]{2,3})", # Eye diameter, integer
+ "[ ]+NM"
+ )
+ as.numeric(stringr::str_match(contents, ptn)[, 2])
}
#' @title fstadv_fcst
@@ -162,7 +162,6 @@ fstadv_forecasts <- function(content, key, adv, adv_date) {
# prefix, eliminate some vars where necessary, and return a filtered
# dataframe.
rebuild_forecasts <- function(hr, df) {
-
df <-
df %>%
dplyr::filter(.data$FcstPeriod == hr) %>%
@@ -199,34 +198,35 @@ fstadv_forecasts <- function(content, key, adv, adv_date) {
} else {
df
}
-
}
- ptn <- stringr::str_c("([:digit:]{2})/([:digit:]{2})([:digit:]{2})Z",
- "[:blank:]+([:digit:]{1,2}\\.[:digit:])([N|S])",
- "[:blank:]+([:digit:]{1,3}\\.[:digit:]{1})([E|W])",
- "[[:space:][:punct:][:alpha:]]+",
- "MAX WIND[:blank:]+([:digit:]{1,3})[:blank:]*KT",
- "[[:blank:][:punct:]]+GUSTS[:blank:]+",
- "([:digit:]{1,3})[:blank:]*KT[[:space:][:punct:]]+",
- "(?:64 KT[[:blank:][:punct:]]+",
- "([:digit:]{1,3})NE",
- "[:blank:]+([:digit:]{1,3})SE",
- "[:blank:]+([:digit:]{1,3})SW",
- "[:blank:]+([:digit:]{1,3})NW",
- "[[:punct:][:space:]]+)?",
- "(?:50 KT[[:blank:][:punct:]]+",
- "([:digit:]{1,3})NE",
- "[:blank:]+([:digit:]{1,3})SE",
- "[:blank:]+([:digit:]{1,3})SW",
- "[:blank:]+([:digit:]{1,3})NW",
- "[[:punct:][:space:]]+)?",
- "(?:34 KT[[:blank:][:punct:]]+",
- "([:digit:]{1,3})NE",
- "[:blank:]+([:digit:]{1,3})SE",
- "[:blank:]+([:digit:]{1,3})SW",
- "[:blank:]+([:digit:]{1,3})NW",
- "[[:punct:][:space:]]+)?")
+ ptn <- stringr::str_c(
+ "([:digit:]{2})/([:digit:]{2})([:digit:]{2})Z",
+ "[:blank:]+([:digit:]{1,2}\\.[:digit:])([N|S])",
+ "[:blank:]+([:digit:]{1,3}\\.[:digit:]{1})([E|W])",
+ "[[:space:][:punct:][:alpha:]]+",
+ "MAX WIND[:blank:]+([:digit:]{1,3})[:blank:]*KT",
+ "[[:blank:][:punct:]]+GUSTS[:blank:]+",
+ "([:digit:]{1,3})[:blank:]*KT[[:space:][:punct:]]+",
+ "(?:64 KT[[:blank:][:punct:]]+",
+ "([:digit:]{1,3})NE",
+ "[:blank:]+([:digit:]{1,3})SE",
+ "[:blank:]+([:digit:]{1,3})SW",
+ "[:blank:]+([:digit:]{1,3})NW",
+ "[[:punct:][:space:]]+)?",
+ "(?:50 KT[[:blank:][:punct:]]+",
+ "([:digit:]{1,3})NE",
+ "[:blank:]+([:digit:]{1,3})SE",
+ "[:blank:]+([:digit:]{1,3})SW",
+ "[:blank:]+([:digit:]{1,3})NW",
+ "[[:punct:][:space:]]+)?",
+ "(?:34 KT[[:blank:][:punct:]]+",
+ "([:digit:]{1,3})NE",
+ "[:blank:]+([:digit:]{1,3})SE",
+ "[:blank:]+([:digit:]{1,3})SW",
+ "[:blank:]+([:digit:]{1,3})NW",
+ "[[:punct:][:space:]]+)?"
+ )
quads <- c("NE", "SE", "SW", "NW")
@@ -241,17 +241,21 @@ fstadv_forecasts <- function(content, key, adv, adv_date) {
# purrr::map(`[`, , 2:22) %>%
# If any storm has 0 forecasts (i.e., the list element is empty), populate
# all columns with NA
- purrr::modify_if(.p = purrr::is_empty,
- .f = ~matrix(data = NA_character_, ncol = 22)) %>%
+ purrr::modify_if(
+ .p = purrr::is_empty,
+ .f = ~ matrix(data = NA_character_, ncol = 22)
+ ) %>%
# Convert to tibble cause God I hate working with lists like this though I
# know I need the practice...
purrr::map(tibble::as_tibble) %>%
- purrr::map(rlang::set_names,
- nm = c("String", "Date", "Hour", "Minute",
- "Lat", "LatHemi", "Lon", "LonHemi",
- "Wind", "Gust", stringr::str_c(quads, "64"),
- stringr::str_c(quads, "50"),
- stringr::str_c(quads, "34")))
+ purrr::map(
+ rlang::set_names,
+ nm = c(
+ "String", "Date", "Hour", "Minute", "Lat", "LatHemi", "Lon", "LonHemi",
+ "Wind", "Gust", stringr::str_c(quads, "64"),
+ stringr::str_c(quads, "50"), stringr::str_c(quads, "34")
+ )
+ )
forecast_periods <- c(12, 24, 36, 48, 72, 96, 120)
@@ -281,11 +285,11 @@ fstadv_forecasts <- function(content, key, adv, adv_date) {
FcstPeriod = forecast_periods[1:dplyr::n()],
FcstMonth = dplyr::case_when(
as.numeric(.data$Date) < lubridate::day(.data$AdvDate) ~ lubridate::month(.data$AdvDate) + 1,
- TRUE ~ lubridate::month(.data$AdvDate)
+ TRUE ~ lubridate::month(.data$AdvDate)
),
FcstYear = dplyr::case_when(
FcstMonth < lubridate::month(.data$AdvDate) ~ lubridate::year(.data$AdvDate) + 1,
- TRUE ~ lubridate::year(.data$AdvDate)
+ TRUE ~ lubridate::year(.data$AdvDate)
),
FcstDate = lubridate::ymd_hms(
strftime(
@@ -300,12 +304,12 @@ fstadv_forecasts <- function(content, key, adv, adv_date) {
# If Lat is in southern hemisphere (unlikely, but possible), make negative
Lat = dplyr::case_when(
LatHemi == "S" ~ as.numeric(.data$Lat) * -1,
- TRUE ~ as.numeric(.data$Lat)
+ TRUE ~ as.numeric(.data$Lat)
),
# If Lon in western hemisphere (most likely), make negative.
Lon = dplyr::case_when(
LonHemi == "W" ~ as.numeric(.data$Lon) * -1,
- TRUE ~ as.numeric(.data$Lon)
+ TRUE ~ as.numeric(.data$Lon)
)
) %>%
# Make Wind, Gust, relative wind/gust vars and sea vars all numeric
@@ -317,7 +321,8 @@ fstadv_forecasts <- function(content, key, adv, adv_date) {
df <-
df %>%
dplyr::left_join(
- rebuild_forecasts(hr, df = df_forecasts), by = c("Key", "Adv")
+ rebuild_forecasts(hr, df = df_forecasts),
+ by = c("Key", "Adv")
)
}
@@ -325,7 +330,6 @@ fstadv_forecasts <- function(content, key, adv, adv_date) {
dplyr::ungroup() %>%
dplyr::select(-c(.data$Key, .data$Adv)) %>%
split(seq(nrow(.)))
-
}
#' @title fstadv_fwd_mvmt
@@ -340,14 +344,14 @@ fstadv_forecasts <- function(content, key, adv, adv_date) {
#' @return numeric
#' @keywords internal
fstadv_fwd_mvmt <- function(contents, what = NULL) {
-
- ptn <- stringr::str_c("PRESENT MOVEMENT TOWARD[[:alpha:][:punct:][:space:]]+",
- "([:digit:]{1,3})[:blank:]+DEGREES AT[:blank:]+",
- "([:digit:]{1,3})[:blank:]KT")
+ ptn <- stringr::str_c(
+ "PRESENT MOVEMENT TOWARD[[:alpha:][:punct:][:space:]]+",
+ "([:digit:]{1,3})[:blank:]+DEGREES AT[:blank:]+",
+ "([:digit:]{1,3})[:blank:]KT"
+ )
matches <- stringr::str_match(contents, ptn)
- matrix(data = c(as.numeric(matches[,2]), as.numeric(matches[,3])), ncol = 2L)
-
+ matrix(data = c(as.numeric(matches[, 2]), as.numeric(matches[, 3])), ncol = 2L)
}
#' @title fstadv_pos_accuracy()
@@ -357,7 +361,7 @@ fstadv_fwd_mvmt <- function(contents, what = NULL) {
#' @keywords internal
fstadv_pos_accuracy <- function(contents) {
ptn <- stringr::str_c("POSITION ACCURATE WITHIN[:blank:]+([0-9]{2,3})[:blank:]+NM")
- as.numeric(stringr::str_match(contents, ptn)[,2])
+ as.numeric(stringr::str_match(contents, ptn)[, 2])
}
#' @title fstadv_pressure
@@ -367,30 +371,40 @@ fstadv_pos_accuracy <- function(contents) {
#' @return numeric
#' @keywords internal
fstadv_pressure <- function(contents) {
- ptn <- stringr::str_c("MINIMUM CENTRAL PRESSURE[:blank:]+",
- "([:digit:]{3,4})[:blank:]*MB")
- as.numeric(stringr::str_match(contents, ptn)[,2])
+ ptn <- stringr::str_c(
+ "MINIMUM CENTRAL PRESSURE[:blank:]+",
+ "([:digit:]{3,4})[:blank:]*MB"
+ )
+ as.numeric(stringr::str_match(contents, ptn)[, 2])
}
#' @title fstadv_prev_pos
#' @description Get storm's previous position
#' @keywords internal
fstadv_prev_pos <- function(contents, adv_date) {
-
ptn <- "AT \\d\\d/\\d{4}Z CENTER WAS LOCATED NEAR (\\d\\d\\.\\d)(\\w)\\s+(\\d{1,3}\\.\\d)(\\w)"
- matches <- stringr::str_match(contents, ptn)[,2:5]
+
+ matches <- stringr::str_match(contents, ptn)[, 2:5]
prev_pos_date <- adv_date - lubridate::hours(3)
- prev_pos_lat <- ifelse(matches[,2] == "S",
- as.numeric(matches[,1]) * -1,
- as.numeric(matches[,1]))
- prev_pos_lon <- ifelse(matches[,4] == "W",
- as.numeric(matches[,3]) * -1,
- as.numeric(matches[,3]))
+
+ prev_pos_lat <- ifelse(
+ matches[, 2] == "S",
+ as.numeric(matches[, 1]) * -1,
+ as.numeric(matches[, 1])
+ )
+
+ prev_pos_lon <- ifelse(
+ matches[, 4] == "W",
+ as.numeric(matches[, 3]) * -1,
+ as.numeric(matches[, 3])
+ )
+
tibble::tibble(
PrevPosDate = prev_pos_date,
PrevPosLat = prev_pos_lat,
- PrevPosLon = prev_pos_lon) %>%
+ PrevPosLon = prev_pos_lon
+ ) %>%
split(seq(nrow(.)))
}
@@ -404,23 +418,28 @@ fstadv_prev_pos <- function(contents, adv_date) {
#' @return numeric
#' @keywords internal
fstadv_lat_lon <- function(contents) {
-
- ptn <- stringr::str_c("[CENTER LOCATED | DISSIPATING] NEAR[:blank:]+",
- "([0-9\\.]{3,4})", # Latitude can be 9.9N or 99.9N
- "([N|S]{1})", # Northern meisphere
- "[:blank:]+([0-9\\.]{4,5})", #Longitude can be 0 to 180
- "([E|W]){1}", # Hemisphere
- "[:blank:]+")
+ ptn <- stringr::str_c(
+ "[CENTER LOCATED | DISSIPATING] NEAR[:blank:]+",
+ "([0-9\\.]{3,4})", # Latitude can be 9.9N or 99.9N
+ "([N|S]{1})", # Northern meisphere
+ "[:blank:]+([0-9\\.]{4,5})", # Longitude can be 0 to 180
+ "([E|W]){1}", # Hemisphere
+ "[:blank:]+"
+ )
matches <- stringr::str_match(contents, ptn)
- lat <- ifelse(matches[, 3] == "S",
- as.numeric(matches[, 2]) * -1,
- as.numeric(matches[, 2]) * 1)
+ lat <- ifelse(
+ matches[, 3] == "S",
+ as.numeric(matches[, 2]) * -1,
+ as.numeric(matches[, 2]) * 1
+ )
- lon <- ifelse(matches[, 5] == "W",
- as.numeric(matches[, 4]) * -1,
- as.numeric(matches[, 4]) * 1)
+ lon <- ifelse(
+ matches[, 5] == "W",
+ as.numeric(matches[, 4]) * -1,
+ as.numeric(matches[, 4]) * 1
+ )
matrix(data = c(lat, lon), ncol = 2)
}
@@ -434,13 +453,15 @@ fstadv_lat_lon <- function(contents) {
fstadv_seas <- function(content) {
# 12 FT SEAS..125NE 90SE 90SW 175NW.
- ptn <- stringr::str_c("12 FT SEAS",
- "[[:punct:][:blank:]]+([0-9]{1,3})NE",
- "[:blank:]+([0-9]{1,3})SE",
- "[:blank:]+([0-9]{1,3})SW",
- "[:blank:]+([0-9]{1,3})NW")
+ ptn <- stringr::str_c(
+ "12 FT SEAS",
+ "[[:punct:][:blank:]]+([0-9]{1,3})NE",
+ "[:blank:]+([0-9]{1,3})SE",
+ "[:blank:]+([0-9]{1,3})SW",
+ "[:blank:]+([0-9]{1,3})NW"
+ )
- stringr::str_match(content, ptn)[,2:5] %>%
+ stringr::str_match(content, ptn)[, 2:5] %>%
apply(MARGIN = 2L, FUN = as.numeric) %>%
tibble::as_tibble() %>%
rlang::set_names(nm = stringr::str_c("Seas", c("NE", "SE", "SW", "NW"))) %>%
@@ -461,32 +482,35 @@ fstadv_seas <- function(content) {
#' @return dataframe
#' @keywords internal
fstadv_wind_radius <- function(content) {
+ ptn <- stringr::str_c(
+ "MAX SUSTAINED WINDS[:blank:]+[:digit:]{1,3} KT ",
+ "WITH GUSTS TO[:blank:]+[:digit:]{1,3} ",
+ "KT[[:punct:][:space:][:upper:]]+",
+ "(?:(64) KT[[:blank:][:punct:]]+([:digit:]{1,3})",
+ "NE[:blank:]+([:digit:]{1,3})",
+ "SE[:blank:]+([:digit:]{1,3})",
+ "SW[:blank:]+([:digit:]{1,3})",
+ "NW[[:punct:][:space:]]+)?",
+ "(?:(50) KT[[:blank:][:punct:]]+([:digit:]{1,3})",
+ "NE[:blank:]+([:digit:]{1,3})",
+ "SE[:blank:]+([:digit:]{1,3})",
+ "SW[:blank:]+([:digit:]{1,3})",
+ "NW[[:punct:][:space:]]+)?",
+ "(?:(34) KT[[:blank:][:punct:]]+([:digit:]{1,3})",
+ "NE[:blank:]+([:digit:]{1,3})",
+ "SE[:blank:]+([:digit:]{1,3})",
+ "SW[:blank:]+([:digit:]{1,3})",
+ "NW[[:punct:][:space:]]+)?"
+ )
- ptn <- stringr::str_c("MAX SUSTAINED WINDS[:blank:]+[:digit:]{1,3} KT ",
- "WITH GUSTS TO[:blank:]+[:digit:]{1,3} ",
- "KT[[:punct:][:space:][:upper:]]+",
- "(?:(64) KT[[:blank:][:punct:]]+([:digit:]{1,3})",
- "NE[:blank:]+([:digit:]{1,3})",
- "SE[:blank:]+([:digit:]{1,3})",
- "SW[:blank:]+([:digit:]{1,3})",
- "NW[[:punct:][:space:]]+)?",
- "(?:(50) KT[[:blank:][:punct:]]+([:digit:]{1,3})",
- "NE[:blank:]+([:digit:]{1,3})",
- "SE[:blank:]+([:digit:]{1,3})",
- "SW[:blank:]+([:digit:]{1,3})",
- "NW[[:punct:][:space:]]+)?",
- "(?:(34) KT[[:blank:][:punct:]]+([:digit:]{1,3})",
- "NE[:blank:]+([:digit:]{1,3})",
- "SE[:blank:]+([:digit:]{1,3})",
- "SW[:blank:]+([:digit:]{1,3})",
- "NW[[:punct:][:space:]]+)?")
-
- stringr::str_match(content, ptn)[,2:16] %>%
+ stringr::str_match(content, ptn)[, 2:16] %>%
apply(MARGIN = 2L, FUN = as.numeric) %>%
tibble::as_tibble() %>%
- rlang::set_names(nm = c("WindField64", "NE64", "SE64", "SW64", "NW64",
- "WindField50", "NE50", "SE50", "SW50", "NW50",
- "WindField34", "NE34", "SE34", "SW34", "NW34")) %>%
+ rlang::set_names(nm = c(
+ "WindField64", "NE64", "SE64", "SW64", "NW64",
+ "WindField50", "NE50", "SE50", "SW50", "NW50",
+ "WindField34", "NE34", "SE34", "SW34", "NW34"
+ )) %>%
dplyr::select(-tidyselect::starts_with("WindField")) %>%
split(seq(nrow(.)))
}
@@ -497,17 +521,17 @@ fstadv_wind_radius <- function(content) {
#' @return numeric
#' @keywords internal
fstadv_winds_gusts <- function(contents) {
-
- ptn <- stringr::str_c('MAX SUSTAINED WINDS[ ]+',
- '([0-9]{2,3})', # Winds
- '[ ]+KT WITH GUSTS TO[ ]+',
- '([0-9]{2,3})', # Gusts
- '[ ]+KT')
+ ptn <- stringr::str_c(
+ "MAX SUSTAINED WINDS[ ]+",
+ "([0-9]{2,3})", # Winds
+ "[ ]+KT WITH GUSTS TO[ ]+",
+ "([0-9]{2,3})", # Gusts
+ "[ ]+KT"
+ )
matches <- stringr::str_match(contents, ptn)
- matrix(data = c(as.numeric(matches[,2]), as.numeric(matches[,3])), ncol = 2L)
-
+ matrix(data = c(as.numeric(matches[, 2]), as.numeric(matches[, 3])), ncol = 2L)
}
#' @title tidy_adv
@@ -542,15 +566,19 @@ fstadv_winds_gusts <- function(contents) {
#' }
#' @export
tidy_adv <- function(df) {
- if (!is.data.frame(df))
+ if (!is.data.frame(df)) {
stop("Expecting a dataframe.")
+ }
+
df <- df %>%
dplyr::select(
"Key",
.data$Adv:.data$Date,
.data$Status:.data$Name,
.data$Lat:.data$Eye,
- dplyr::starts_with("Seas"))
+ dplyr::starts_with("Seas")
+ )
+
return(df)
}
@@ -560,7 +588,9 @@ tidy_adv <- function(df) {
#' @export
tidy_fstadv <- function(df) {
.Deprecated("tidy_adv",
- msg = "`tidy_fstadv is deprecated and will be removed in v0.2.2")
+ msg = "`tidy_fstadv is deprecated and will be removed in v0.2.2"
+ )
+
tidy_adv(df)
}
@@ -586,8 +616,9 @@ tidy_fstadv <- function(df) {
#' }
#' @export
tidy_wr <- function(df) {
- if (!is.data.frame(df))
+ if (!is.data.frame(df)) {
stop("Expecting a dataframe.")
+ }
# Collapse wind radius fields to narrow dataframe then expand on the four
# quadrants, keeping WindField as a variable.
@@ -605,9 +636,11 @@ tidy_wr <- function(df) {
"NE" = paste0("NE", y),
"SE" = paste0("SE", y),
"SW" = paste0("SW", y),
- "NW" = paste0("NW", y)) %>%
+ "NW" = paste0("NW", y)
+ ) %>%
dplyr::mutate("WindField" = y)
- }) %>%
+ }
+ ) %>%
dplyr::select(c(
"Key", "Adv", "Date", "WindField", .data$NE:.data$NW
)) %>%
@@ -615,7 +648,7 @@ tidy_wr <- function(df) {
dplyr::arrange(.data$Key, .data$Date, .data$Adv, .data$WindField)
# Remove NA rows for windfield quadrants
- wr <- wr[stats::complete.cases(wr$NE, wr$SE, wr$SW, wr$NW),]
+ wr <- wr[stats::complete.cases(wr$NE, wr$SE, wr$SW, wr$NW), ]
return(wr)
}
@@ -644,8 +677,9 @@ tidy_wr <- function(df) {
#' }
#' @export
tidy_fcst <- function(df) {
- if (!is.data.frame(df))
+ if (!is.data.frame(df)) {
stop("Expecting a dataframe.")
+ }
# Build forecasts dataframe with base data for each forecast position. This
# does not include wind radius data; that comes next. This will be similar
@@ -659,7 +693,7 @@ tidy_fcst <- function(df) {
# #107 Modified regex pattern to look for Hr120, as well.
fcst_periods <- as.list(names(df)) %>%
stringr::str_match(pattern = "Hr([:digit:]{2,3})FcstDate") %>%
- .[,2] %>%
+ .[, 2] %>%
.[!rlang::are_na(.)] %>%
as.numeric()
@@ -668,18 +702,26 @@ tidy_fcst <- function(df) {
.f = function(y) {
df %>%
dplyr::select(c("Key", "Adv", "Date", paste0("Hr", y, v))) %>%
- dplyr::rename("Key" = "Key", "Adv" = "Adv", "Date" = "Date",
- "FcstDate" = paste0("Hr", y, "FcstDate"),
- "Lat" = paste0("Hr", y, "Lat"),
- "Lon" = paste0("Hr", y, "Lon"),
- "Wind" = paste0("Hr", y, "Wind"),
- "Gust" = paste0("Hr", y, "Gust"))}) %>%
+ dplyr::rename(
+ "Key" = "Key",
+ "Adv" = "Adv",
+ "Date" = "Date",
+ "FcstDate" = paste0("Hr", y, "FcstDate"),
+ "Lat" = paste0("Hr", y, "Lat"),
+ "Lon" = paste0("Hr", y, "Lon"),
+ "Wind" = paste0("Hr", y, "Wind"),
+ "Gust" = paste0("Hr", y, "Gust")
+ )
+ }
+ ) %>%
dplyr::arrange(.data$Key, .data$Date, .data$Adv, .data$FcstDate)
# Remove NA rows
forecasts <- forecasts[stats::complete.cases(
forecasts$FcstDate, forecasts$Lat, forecasts$Lon, forecasts$Wind,
- forecasts$Gust),]
+ forecasts$Gust
+ ), ]
+
return(forecasts)
}
@@ -708,9 +750,9 @@ tidy_fcst <- function(df) {
#' }
#' @export
tidy_fcst_wr <- function(df) {
-
- if (!is.data.frame(df))
+ if (!is.data.frame(df)) {
stop("Expecting a dataframe.")
+ }
# Build wind radius dataframe for each forecast position (12:72 hours; 96
# and 120 hours are never forecasted). This dataframe will be similar to
@@ -721,7 +763,7 @@ tidy_fcst_wr <- function(df) {
# What forecast periods are in the current dataset?
fcst_periods <- as.list(names(df)) %>%
stringr::str_match(pattern = "Hr([:digit:]{2})FcstDate") %>%
- .[,2] %>%
+ .[, 2] %>%
.[!rlang::are_na(.)] %>%
as.numeric()
@@ -730,9 +772,10 @@ tidy_fcst_wr <- function(df) {
.f = function(x) {
if (x %in% c(12, 24, 36)) fcst_wind_radii <- c(34, 50, 64)
if (x %in% c(48, 72)) fcst_wind_radii <- c(34, 50)
- if (x %in% c(96, 120)) return(NULL)
+ if (x %in% c(96, 120)) {
+ return(NULL)
+ }
y <- purrr::map_df(.x = fcst_wind_radii, .f = function(z) {
-
df %>%
dplyr::select(c(
"Key", "Adv", "Date", paste0("Hr", x, "FcstDate"),
@@ -746,23 +789,27 @@ tidy_fcst_wr <- function(df) {
"NE" = paste0("Hr", x, "NE", z),
"SE" = paste0("Hr", x, "SE", z),
"SW" = paste0("Hr", x, "SW", z),
- "NW" = paste0("Hr", x, "NW", z)) %>%
+ "NW" = paste0("Hr", x, "NW", z)
+ ) %>%
dplyr::mutate("WindField" = z) %>%
dplyr::select(c(
.data$Key:.data$FcstDate,
"WindField",
- .data$NE:.data$NW))
- })
+ .data$NE:.data$NW
+ ))
+ })
+
return(y)
- })
+ }
+ )
fcst_wr <- dplyr::arrange(
fcst_wr, .data$Key, .data$Date, .data$Adv, .data$FcstDate, .data$WindField
)
fcst_wr <- fcst_wr[stats::complete.cases(
- fcst_wr$NE, fcst_wr$SE, fcst_wr$SW, fcst_wr$NW),]
+ fcst_wr$NE, fcst_wr$SE, fcst_wr$SW, fcst_wr$NW
+ ), ]
return(fcst_wr)
-
}
diff --git a/R/get_storm_data.R b/R/get_storm_data.R
index 864ee38f..54e3f467 100644
--- a/R/get_storm_data.R
+++ b/R/get_storm_data.R
@@ -4,7 +4,6 @@
#' @param product specific product to parse
#' @keywords internal
extract_product_contents <- function(links, product) {
-
contents <- get_url_contents(links)
# Some products may not exist within HTML but as strict text.
@@ -13,7 +12,7 @@ extract_product_contents <- function(links, product) {
contents <-
links %>%
- get_url_contents() %>% # Read in contents as html
+ get_url_contents() %>% # Read in contents as html
# If text is not within html, then we simply need to return the text.
# Otherwise, extract the node from within the HTML and return the text of
# that node.
@@ -31,7 +30,6 @@ extract_product_contents <- function(links, product) {
})
purrr::invoke_map_df(product, .x = list(list(contents)))
-
}
#' @title extract_storm_links
@@ -39,9 +37,9 @@ extract_product_contents <- function(links, product) {
#' @param links URLs to a storm's archive page
#' @keywords internal
extract_storm_links <- function(links) {
-
- if (!is.vector(links))
+ if (!is.vector(links)) {
stop("Links must be a character vector.", call. = FALSE)
+ }
# Get links of text products from each `links`
product_links <-
@@ -49,12 +47,12 @@ extract_storm_links <- function(links) {
get_url_contents() %>%
purrr::imap(.f = xml2::read_html) %>%
# Extract the html tables from each link to get the storm's text products
- purrr::imap(.f = ~rvest::html_nodes(.x, xpath = "//td//a")) %>%
+ purrr::imap(.f = ~ rvest::html_nodes(.x, xpath = "//td//a")) %>%
# Extract the text product URLs from `nodes`
- purrr::imap(.f = ~rvest::html_attr(.x, name = "href")) %>%
+ purrr::imap(.f = ~ rvest::html_attr(.x, name = "href")) %>%
purrr::flatten_chr() %>%
# Ensure we're only capturing archive pages
- stringr::str_match( "archive.+") %>%
+ stringr::str_match("archive.+") %>%
.[stats::complete.cases(.)]
# Extract years from `links`
@@ -64,8 +62,10 @@ extract_storm_links <- function(links) {
# other years, product_links are absolute. If product_links exist for 1998
# they must be modified. All product_links must then be prefixed with
# NHC URL.
- product_links[years == 1998] <- stringr::str_c("/archive/1998/",
- product_links[years == 1998])
+ product_links[years == 1998] <- stringr::str_c(
+ "/archive/1998/",
+ product_links[years == 1998]
+ )
product_links <- stringr::str_c(get_nhc_link(), product_links)
}
@@ -128,10 +128,11 @@ get_product <- function(links, product) {
#' get_storm_data(products = c("discus", "public"))
#' }
#' @export
-get_storm_data <- function(links, products = c("discus", "fstadv", "posest",
- "public", "prblty", "update",
- "wndprb")) {
-
+get_storm_data <- function(links, products = c(
+ "discus", "fstadv", "posest",
+ "public", "prblty", "update",
+ "wndprb"
+ )) {
products <- match.arg(products, several.ok = TRUE)
product_links <- extract_storm_links(links)
@@ -144,6 +145,8 @@ get_storm_data <- function(links, products = c("discus", "fstadv", "posest",
product_links <- rlang::set_names(product_links, nm = products)
- purrr::map2(product_links, products, extract_product_contents)
+ # Filter out empty list elements
+ product_links <- Filter(length, product_links)
+ purrr::map2(product_links, names(product_links), extract_product_contents)
}
diff --git a/R/get_storm_list.R b/R/get_storm_list.R
index a5c7ebaa..b6cb9d41 100644
--- a/R/get_storm_list.R
+++ b/R/get_storm_list.R
@@ -3,29 +3,17 @@
#' @export
get_storm_list <- function() {
- # 2018-12-29 - On Dec. 9, an update was made putting a newline at the
- # beginning of the text file. This threw off the original code generating
- # warnings. Instead of reading directly as CSV, read in as character, trim
- # whitespace, then read CSV.
-
- # Read in file as string
- txt <- readChar(
- "ftp://ftp.nhc.noaa.gov/atcf/index/storm_list.txt",
- nchars = 252928)
-
- # Remove any trailing white space
- clean_txt <- stringr::str_trim(txt)
-
# Return dataframe
- readr::read_csv(
- file = clean_txt,
- col_names = c(
- "STORM_NAME", "RE", "X", "R2", "R3", "R4", "R5", "CY", "YYYY", "TY",
- "I", "YYY1MMDDHH", "YYY2MMDDHH", "SIZE", "GENESIS_NUM", "PAR1", "PAR2",
- "PRIORITY", "STORM_STATE", "WT_NUMBER", "STORMID"
- ),
- col_types = "ccccccciiccccciccicic"
- ) %>%
+ storm_list <-
+ readr::read_csv(
+ file = "ftp://ftp.nhc.noaa.gov/atcf/index/storm_list.txt",
+ col_names = c(
+ "STORM_NAME", "RE", "X", "R2", "R3", "R4", "R5", "CY", "YYYY", "TY",
+ "I", "YYY1MMDDHH", "YYY2MMDDHH", "SIZE", "GENESIS_NUM", "PAR1", "PAR2",
+ "PRIORITY", "STORM_STATE", "WT_NUMBER", "STORMID"
+ ),
+ col_types = "ccccccciiccccciccicic"
+ ) %>%
dplyr::mutate_at(
.vars = c("YYY1MMDDHH", "YYY2MMDDHH"),
.f = as.POSIXct,
@@ -63,11 +51,12 @@ get_ftp_dirs <- function(x) {
#' @export
#' @seealso \code{\link{get_storm_data}}
get_ftp_storm_data <- function(stormid,
- products = c("discus", "fstadv", "posest",
- "public", "prblty", "update",
- "wndprb")) {
-
- if (!grepl("(AL|EP)\\d{6}", stormid))
+ products = c(
+ "discus", "fstadv", "posest",
+ "public", "prblty", "update",
+ "wndprb"
+ )) {
+ if (!grepl("(AL|EP)\\d{6}", stormid)) {
stop(
stringr::str_c(
"stormid should be an alphanumeric string with the basin abbreviation ",
@@ -76,9 +65,10 @@ get_ftp_storm_data <- function(stormid,
.call = FALSE
)
)
+ }
# What year is the storm?
- yyyy <- as.integer(stringr::str_match(stormid, "^.+(\\d{4})$")[,2])
+ yyyy <- as.integer(stringr::str_match(stormid, "^.+(\\d{4})$")[, 2])
# List all directories in the ftp's archives
archives <- get_ftp_dirs(x = "/atcf/archive/")
@@ -145,7 +135,8 @@ get_ftp_storm_data <- function(stormid,
dplyr::pull(.data$Name)
pkg <- sprintf(
- fmt = "ftp://ftp.nhc.noaa.gov/atcf/archive/%s/messages/%s",
+ fmt = "%satcf/archive/%s/messages/%s",
+ get_nhc_ftp_link(),
yyyy,
links
)
@@ -192,18 +183,17 @@ get_ftp_storm_data <- function(stormid,
files_length <- purrr::map(.x = files, .f = file.info) %>%
purrr::map_dbl("size")
res_txt <- purrr::map2_chr(.x = files, .y = files_length, readChar)
-
} else {
links <- sprintf(
- fmt = "ftp://ftp.nhc.noaa.gov/atcf/archive/%s/messages/%s",
+ fmt = "%satcf/archive/%s/messages/%s",
+ get_nhc_ftp_link(),
yyyy,
links
)
res <- get_url_contents(links)
- res_parsed <- purrr::map(res, ~xml2::read_html(.$content))
+ res_parsed <- purrr::map(res, ~ xml2::read_html(.$content))
res_txt <- purrr::map_chr(res_parsed, rvest::html_text)
-
}
} else {
# If the `yyyy` value is not in the ftp archives, then it is in a product
@@ -226,39 +216,53 @@ get_ftp_storm_data <- function(stormid,
"wndprb" = "wndprb"
)
+ # Because some products may be requested that do not exist (i.e., update,
+ # posest, filter out, just in case)
+ products <- products[which(products %in% names(named_products))]
ftp_subdir <- sprintf("atcf/%s/", named_products[products])
- ftp_contents <- get_ftp_dirs(ftp_subdir)
+ ftp_contents <- purrr::map(ftp_subdir, get_ftp_dirs)
- links <-
+ ftp_content_links <-
ftp_contents %>%
- dplyr::filter(
- grepl(
- pattern =
- sprintf(
- fmt = "^%s\\.%s\\.\\d{3}$",
- stringr::str_to_lower(stormid),
- products
- ),
- x = .data$Name
+ purrr::map2(ftp_subdir, ~paste0(.y, .x$Name))
+
+ # Make sure we're only using the links for the requested storm; filter out
+ # all others.
+ filtered_links <-
+ purrr::map(
+ .x = seq_along(ftp_content_links),
+ .f = ~grep(
+ pattern = paste0(".+", stormid, ".+"),
+ x = ftp_content_links[[.x]],
+ ignore.case = TRUE,
+ value = TRUE
)
- ) %>%
- dplyr::pull(.data$Name)
+ )
- links <- sprintf(
- fmt = "ftp://ftp.nhc.noaa.gov/atcf/%s/%s",
- named_products[products],
- links
- )
+ # Set names of list to products
+ names(filtered_links) <- products
- res <- get_url_contents(links)
- res_parsed <- purrr::map(res, ~xml2::read_html(.$content))
- res_txt <- purrr::map_chr(res_parsed, rvest::html_text)
+ # Make full links
+ full_links <- purrr::map(
+ .x = filtered_links,
+ .f = ~sprintf(
+ fmt = "%s%s",
+ get_nhc_ftp_link(),
+ .x
+ )
+ )
+ res_txt <- purrr::map(full_links, get_url_contents)
}
- df <- purrr::invoke_map_df(
- .f = utils::getFromNamespace(x = products, ns = "rrricanes"),
- .x = res_txt
- )
+ df <-
+ purrr::map(
+ .x = names(res_txt),
+ .f = ~rlang::exec(
+ .fn = utils::getFromNamespace(x = .x, ns = "rrricanes"),
+ contents = res_txt[[.x]]
+ )
+ ) %>%
+ rlang::set_names(nm = names(res_txt))
}
diff --git a/R/get_storms.R b/R/get_storms.R
index 4e01842c..4088435f 100644
--- a/R/get_storms.R
+++ b/R/get_storms.R
@@ -5,7 +5,6 @@
#' @return 4xN Dataframe
#' @keywords internal
extract_storms <- function(basin, contents) {
-
xpaths <- list(
"AL" = "//td[(((count(preceding-sibling::*) + 1) = 1) and parent::*)]//a",
"EP" = "//td[(((count(preceding-sibling::*) + 1) = 2) and parent::*)]//a"
@@ -28,7 +27,7 @@ extract_storms <- function(basin, contents) {
links <-
storms %>%
purrr::map(rvest::html_attr, name = "href") %>%
- purrr::map2(years, ~stringr::str_c(year_archives_link(.y), .x)) %>%
+ purrr::map2(years, ~ stringr::str_c(year_archives_link(.y), .x)) %>%
purrr::flatten_chr()
names <-
@@ -92,16 +91,20 @@ extract_storms <- function(basin, contents) {
#' @export
get_storms <- function(years = format(Sys.Date(), "%Y"),
basins = c("AL", "EP")) {
-
years <- as.integer(years)
- if (!all(years %in% 1998:lubridate::year(Sys.Date())))
- stop(sprintf("Param `years` must be between 1998 and %s.",
- lubridate::year(Sys.Date())),
- call. = FALSE)
+ if (!all(years %in% 1998:lubridate::year(Sys.Date()))) {
+ stop(sprintf(
+ "Param `years` must be between 1998 and %s.",
+ lubridate::year(Sys.Date())
+ ),
+ call. = FALSE
+ )
+ }
- if (!all(basins %in% c("AL", "EP")))
+ if (!all(basins %in% c("AL", "EP"))) {
stop("Basin must 'AL' and/or 'EP'.", call. = FALSE)
+ }
links <-
years %>%
@@ -109,13 +112,14 @@ get_storms <- function(years = format(Sys.Date(), "%Y"),
purrr::flatten_chr()
# 1998 is only year with slightly different URL. Modify accordingly
- links[grep("1998", links)] <- stringr::str_c(links[grep("1998", links)],
- "1998archive.shtml")
+ links[grep("1998", links)] <- stringr::str_c(
+ links[grep("1998", links)],
+ "1998archive.shtml"
+ )
contents <- get_url_contents(links)
purrr::map_df(basins, extract_storms, contents)
-
}
#' @title year_archives_link
@@ -124,5 +128,5 @@ get_storms <- function(years = format(Sys.Date(), "%Y"),
#' @keywords internal
year_archives_link <- function(year) {
nhc_link <- get_nhc_link()
- sprintf(stringr::str_c(nhc_link, 'archive/%i/'), year)
+ sprintf(stringr::str_c(nhc_link, "archive/%i/"), year)
}
diff --git a/R/gis.R b/R/gis.R
index c8aa4229..ae1cc38c 100644
--- a/R/gis.R
+++ b/R/gis.R
@@ -7,46 +7,61 @@
#' @seealso \code{\link{gis_download}}
#' @export
gis_advisory <- function(key, advisory = as.character()) {
-
- if (is.null(key))
+ if (is.null(key)) {
stop("Please provide a `key`.", call. = FALSE)
+ }
key <- stringr::str_to_lower(key)
- if (!grepl("^[[:lower:]]{2}[[:digit:]]{6}$", key))
+ if (!grepl("^[[:lower:]]{2}[[:digit:]]{6}$", key)) {
stop("`key` should be a 8-character alphanumeric string.", call. = FALSE)
+ }
- key <- stringr::str_match(key,
- pattern = stringr::str_c("([:lower:]{2})([:digit:]{2})",
- "([:digit:]{4})"))
+ key <- stringr::str_match(
+ key,
+ pattern = stringr::str_c(
+ "([:lower:]{2})([:digit:]{2})",
+ "([:digit:]{4})"
+ )
+ )
# Get list of GIS forecast zips for storm and download
- url <- sprintf("%sgis/archive_forecast_results.php?id=%s%s&year=%s",
- get_nhc_link(),
- key[,2], # Basin
- key[,3], # Storm number
- key[,4]) # Year
+ url <- sprintf(
+ "%sgis/archive_forecast_results.php?id=%s%s&year=%s",
+ get_nhc_link(),
+ key[, 2], # Basin
+ key[, 3], # Storm number
+ key[, 4]
+ ) # Year
contents <- readr::read_lines(url)
# Match zip files. If advisory is empty then need to pull all zip files for
# the storm. Otherwise, pull only selected advisory.
if (purrr::is_empty(advisory)) {
- ptn <- sprintf(".+(forecast/archive/%s.*?\\.zip).+",
- stringr::str_to_lower(key[,1]))
+ ptn <- sprintf(
+ ".+(forecast/archive/%s.*?\\.zip).+",
+ stringr::str_to_lower(key[, 1])
+ )
} else {
advisory <- stringr::str_match(advisory, "([:digit:]{1,3})([:alpha:]*)")
names(advisory) <- c("original", "advisory", "int_adv")
- ptn <- sprintf(".+(forecast/archive/%s.*?%s%s\\.zip).+",
- stringr::str_to_lower(key[,1]),
- stringr::str_pad(string = advisory[["advisory"]],
- width = 3, side = "left", pad = "0"),
- advisory[["int_adv"]])
+ ptn <- sprintf(
+ ".+(forecast/archive/%s.*?%s%s\\.zip).+",
+ stringr::str_to_lower(key[, 1]),
+ stringr::str_pad(
+ string = advisory[["advisory"]],
+ width = 3, side = "left", pad = "0"
+ ),
+ advisory[["int_adv"]]
+ )
}
- matches <- stringr::str_match(contents, pattern = ptn)[,2]
+ matches <- stringr::str_match(contents, pattern = ptn)[, 2]
matches <- matches[stats::complete.cases(matches)]
- if (purrr::is_empty(matches)) return(NULL)
+ if (purrr::is_empty(matches)) {
+ return(NULL)
+ }
# Append website domain to links
stringr::str_c(get_nhc_link(), "gis/", matches)
@@ -71,7 +86,6 @@ gis_advisory <- function(key, advisory = as.character()) {
#' unofficial and sites not on the list can be selected if conditions warrant.
#' @export
gis_breakpoints <- function() {
-
breakpoint_file <-
stringr::str_c(get_nhc_link, "gis/") %>%
xml2::read_html() %>%
@@ -84,39 +98,23 @@ gis_breakpoints <- function() {
.[stats::complete.cases(.)]
stringr::str_c(get_nhc_link(withTrailingSlash = FALSE), breakpoint_file)
-
}
#' @title gis_download
#' @description Get GIS data for storm.
#' @param url link to GIS dataset to download.
-#' @param ... additional parameters for rgdal::readOGR
+#' @param destdir The destination directory to download and extract the zip file
+#' @param ... additional parameters for file.path
#' @export
-gis_download <- function(url, ...) {
-
- destdir <- tempdir()
+gis_download <- function(url, destdir = tempdir(), ...) {
- utils::download.file(file.path(url), zip_file <- tempfile())
+ utils::download.file(file.path(url), zip_file <- tempfile(), ...)
zip_contents <- utils::unzip(zip_file, list = TRUE)$Name
utils::unzip(zip_file, exdir = destdir)
- shp_files <- stringr::str_match(zip_contents, pattern = ".+shp$")
- shp_files <- shp_files[stats::complete.cases(shp_files)]
-
- ds <-
- purrr::map2(
- .x = destdir,
- .y = stringr::str_replace(shp_files, "\\.shp", ""),
- .f = rgdal::readOGR,
- encoding = "UTF-8",
- stringsAsFactors = FALSE,
- use_iconv = TRUE,
- ...
- )
-
- rlang::set_names(ds, nm = stringr::str_replace(shp_files, "\\.shp", ""))
+ return(zip_contents)
}
@@ -126,23 +124,27 @@ gis_download <- function(url, ...) {
#' @param ... additional parameters for rgdal::readOGR
#' @export
gis_latest <- function(basins = c("AL", "EP"), ...) {
-
- if (!(all(basins %in% c("AL", "EP"))))
+ if (!(all(basins %in% c("AL", "EP")))) {
stop("Basin must be one or both of AL or EP.", call. = FALSE)
+ }
- urls <- list("AL" = stringr::str_c(get_nhc_link(), "gis-at.xml"),
- "EP" = stringr::str_c(get_nhc_link(), "gis-ep.xml"))
+ urls <- list(
+ "AL" = stringr::str_c(get_nhc_link(), "gis-at.xml"),
+ "EP" = stringr::str_c(get_nhc_link(), "gis-ep.xml")
+ )
gis_zips <-
basins %>%
- purrr::map(~xml2::read_xml(urls[[.x]])) %>%
+ purrr::map(~ xml2::read_xml(urls[[.x]])) %>%
purrr::map(~ xml2::xml_find_all(.x, xpath = ".//link") %>%
- xml2::xml_text()) %>%
+ xml2::xml_text()) %>%
purrr::map(stringr::str_match, ".+\\.zip$") %>%
purrr::flatten_chr() %>%
.[!is.na(.)]
- if (purrr::is_empty(gis_zips)) return(NULL)
+ if (purrr::is_empty(gis_zips)) {
+ return(NULL)
+ }
purrr::map(gis_zips, gis_download, ...)
}
@@ -193,50 +195,65 @@ gis_outlook <- function() {
#' gis_prob_storm_surge("AL092016", products = list("psurge" = 0, "esurge" = 10))
#'
#' # Return all psurge0 products for Sep 2, 2016, storm AL092016
-#' gis_prob_storm_surge("AL092016", products = list("psurge" = 0),
-#' datetime = "20160902")
+#' gis_prob_storm_surge("AL092016",
+#' products = list("psurge" = 0),
+#' datetime = "20160902"
+#' )
#' }
#' @export
gis_prob_storm_surge <- function(key, products, datetime = NULL) {
-
- if (is.null(key))
+ if (is.null(key)) {
stop("Please provide a storm `key`.", call. = FALSE)
+ }
# Validate products
- if (!(all(names(products) %in% c("psurge", "esurge"))))
+ if (!(all(names(products) %in% c("psurge", "esurge")))) {
stop("`products` must be 'psurge' and/or 'esurge'.", call. = FALSE)
+ }
- if (!is.null(products[["psurge"]]))
- if (!(all(dplyr::between(products[["psurge"]], 0, 20))))
+ if (!is.null(products[["psurge"]])) {
+ if (!(all(dplyr::between(products[["psurge"]], 0, 20)))) {
stop("'psurge' values must be between 0 and 20.", call. = FALSE)
+ }
+ }
- if (!is.null(products[["esurge"]]))
- if (!(all(products[["esurge"]] %in% seq(10, 50, by = 10))))
+ if (!is.null(products[["esurge"]])) {
+ if (!(all(products[["esurge"]] %in% seq(10, 50, by = 10)))) {
stop("'esurge' values must be 10, 20, 30, 40 or 50.", call. = FALSE)
+ }
+ }
key <- stringr::str_to_lower(key)
- if (!grepl("^[[:lower:]]{2}[[:digit:]]{6}$", key))
+ if (!grepl("^[[:lower:]]{2}[[:digit:]]{6}$", key)) {
stop("`key` should be a 8-character alphanumeric string.", call. = FALSE)
+ }
key <- stringr::str_match(key,
- pattern = stringr::str_c("([:lower:]{2})([:digit:]",
- "{2})([:digit:]{4})"))
+ pattern = stringr::str_c(
+ "([:lower:]{2})([:digit:]",
+ "{2})([:digit:]{4})"
+ )
+ )
# Get list of GIS forecast zips for storm and download
- url <- sprintf("%sgis/archive_psurge_results.php?id=%s%s&year=%s",
- get_nhc_link(),
- key[,2], # Basin
- key[,3], # Storm number
- key[,4]) # Year
+ url <- sprintf(
+ "%sgis/archive_psurge_results.php?id=%s%s&year=%s",
+ get_nhc_link(),
+ key[, 2], # Basin
+ key[, 3], # Storm number
+ key[, 4]
+ ) # Year
contents <- readr::read_lines(url)
# Build product pattern
ptn_product <-
- purrr::map2(.x = names(products),
- .y = products,
- .f = stringr::str_c) %>%
+ purrr::map2(
+ .x = names(products),
+ .y = products,
+ .f = stringr::str_c
+ ) %>%
purrr::flatten_chr()
# Build datetime pattern
@@ -254,15 +271,19 @@ gis_prob_storm_surge <- function(key, products, datetime = NULL) {
}
# Match zip files.
- ptn <- sprintf(".+(storm_surge/%s_(%s)_(%s)\\.zip).+",
- stringr::str_to_lower(key[,1]),
- stringr::str_c(ptn_product, collapse = "|"),
- ptn_datetime)
-
- matches <- stringr::str_match(contents, pattern = ptn)[,2]
+ ptn <- sprintf(
+ ".+(storm_surge/%s_(%s)_(%s)\\.zip).+",
+ stringr::str_to_lower(key[, 1]),
+ stringr::str_c(ptn_product, collapse = "|"),
+ ptn_datetime
+ )
+
+ matches <- stringr::str_match(contents, pattern = ptn)[, 2]
matches <- matches[stats::complete.cases(matches)]
- if (purrr::is_empty(matches)) return(NULL)
+ if (purrr::is_empty(matches)) {
+ return(NULL)
+ }
stringr::str_c(get_nhc_link(), "gis/", matches)
}
@@ -277,54 +298,67 @@ gis_prob_storm_surge <- function(key, products, datetime = NULL) {
gis_storm_surge_flood <- function(key,
advisory = as.numeric(),
products = c("inundation", "tidalmask")) {
-
if (is.null(key)) stop("Please provide a storm `key`.", call. = FALSE)
key <- stringr::str_to_upper(key)
- if (!grepl("^[[:alpha:]]{2}[[:digit:]]{6}$", key))
+ if (!grepl("^[[:alpha:]]{2}[[:digit:]]{6}$", key)) {
stop("`key` should be a 8-character alphanumeric string.", call. = FALSE)
+ }
- if (!(any(products %in% c("inundation", "tidalmask"))))
+ if (!(any(products %in% c("inundation", "tidalmask")))) {
stop("`products` must be 'inundation' or 'tidalmask'.", call. = FALSE)
+ }
key <- stringr::str_match(key,
- pattern = stringr::str_c("([:alpha:]{2})([:digit:]",
- "{2})([:digit:]{4})"))
+ pattern = stringr::str_c(
+ "([:alpha:]{2})([:digit:]",
+ "{2})([:digit:]{4})"
+ )
+ )
# Get list of GIS zips for storm and download
- url <- sprintf("%sgis/archive_inundation_results.php?id=%s%s&year=%s",
- get_nhc_link(),
- key[,2], # Basin
- key[,3], # Storm number
- key[,4]) # Year
+ url <- sprintf(
+ "%sgis/archive_inundation_results.php?id=%s%s&year=%s",
+ get_nhc_link(),
+ key[, 2], # Basin
+ key[, 3], # Storm number
+ key[, 4]
+ ) # Year
contents <- readr::read_lines(url)
if (purrr::is_empty(advisory)) {
- ptn <- sprintf(".+(%s/%s%s%s_[:digit:]{1,2}_(%s)\\.zip).+",
- "inundation/forecasts",
- key[,2],
- key[,3],
- stringr::str_sub(key[,4], start = 3L, end = 4L),
- stringr::str_c(products, collapse = "|"))
+ ptn <- sprintf(
+ ".+(%s/%s%s%s_[:digit:]{1,2}_(%s)\\.zip).+",
+ "inundation/forecasts",
+ key[, 2],
+ key[, 3],
+ stringr::str_sub(key[, 4], start = 3L, end = 4L),
+ stringr::str_c(products, collapse = "|")
+ )
} else {
- ptn <- sprintf(".+(inundation/forecasts/%s%s%s_%s_(%s)\\.zip).+",
- key[,2],
- key[,3],
- stringr::str_sub(key[,4], start = 3L, end = 4L),
- stringr::str_pad(advisory, width = 2, side = "left",
- pad = "0"),
- stringr::str_c(products, collapse = "|"))
+ ptn <- sprintf(
+ ".+(inundation/forecasts/%s%s%s_%s_(%s)\\.zip).+",
+ key[, 2],
+ key[, 3],
+ stringr::str_sub(key[, 4], start = 3L, end = 4L),
+ stringr::str_pad(advisory,
+ width = 2, side = "left",
+ pad = "0"
+ ),
+ stringr::str_c(products, collapse = "|")
+ )
}
- matches <- stringr::str_match(contents, pattern = ptn)[,2]
+ matches <- stringr::str_match(contents, pattern = ptn)[, 2]
matches <- matches[stats::complete.cases(matches)]
- if (purrr::is_empty(matches)) return(NULL)
+ if (purrr::is_empty(matches)) {
+ return(NULL)
+ }
stringr::str_c(get_nhc_link(), "gis/", matches)
-
}
#' @title gis_windfield
@@ -345,47 +379,61 @@ gis_storm_surge_flood <- function(key,
#' @seealso \code{\link{gis_download}}
#' @export
gis_windfield <- function(key, advisory = as.character()) {
-
- if (is.null(key))
+ if (is.null(key)) {
stop("Please provide a storm `key`.", call. = FALSE)
+ }
key <- stringr::str_to_lower(key)
- if (!grepl("^[[:lower:]]{2}[[:digit:]]{6}$", key))
+ if (!grepl("^[[:lower:]]{2}[[:digit:]]{6}$", key)) {
stop("`key` should be a 8-character alphanumeric string.", call. = FALSE)
+ }
key <- stringr::str_match(key,
- pattern = stringr::str_c("([:lower:]{2})([:digit:]",
- "{2})([:digit:]{4})"))
+ pattern = stringr::str_c(
+ "([:lower:]{2})([:digit:]",
+ "{2})([:digit:]{4})"
+ )
+ )
# Get list of GIS forecast zips for storm and download
- url <- sprintf("%sgis/archive_forecast_info_results.php?id=%s%s&year=%s",
- get_nhc_link(),
- key[,2], # Basin
- key[,3], # Storm number
- key[,4]) # Year
+ url <- sprintf(
+ "%sgis/archive_forecast_info_results.php?id=%s%s&year=%s",
+ get_nhc_link(),
+ key[, 2], # Basin
+ key[, 3], # Storm number
+ key[, 4]
+ ) # Year
contents <- readr::read_lines(url)
# Match zip files. If advisory is empty then need to pull all zip files for
# the storm. Otherwise, pull only selected advisory.
if (purrr::is_empty(advisory)) {
- ptn <- sprintf(".+(forecast/archive/%s.*?\\.zip).+",
- stringr::str_to_lower(key[,1]))
+ ptn <- sprintf(
+ ".+(forecast/archive/%s.*?\\.zip).+",
+ stringr::str_to_lower(key[, 1])
+ )
} else {
advisory <- stringr::str_match(advisory, "([:digit:]{1,3})([:alpha:]*)")
names(advisory) <- c("original", "advisory", "int_adv")
- ptn <- sprintf(".+(forecast/archive/%s.*?%s%s\\.zip).+",
- stringr::str_to_lower(key[,1]),
- stringr::str_pad(string = advisory[["advisory"]],
- width = 3, side = "left", pad = "0"),
- advisory[["int_adv"]])
+ ptn <- sprintf(
+ ".+(forecast/archive/%s.*?%s%s\\.zip).+",
+ stringr::str_to_lower(key[, 1]),
+ stringr::str_pad(
+ string = advisory[["advisory"]],
+ width = 3, side = "left", pad = "0"
+ ),
+ advisory[["int_adv"]]
+ )
}
- matches <- stringr::str_match(contents, pattern = ptn)[,2]
+ matches <- stringr::str_match(contents, pattern = ptn)[, 2]
matches <- matches[stats::complete.cases(matches)]
- if (purrr::is_empty(matches)) return(NULL)
+ if (purrr::is_empty(matches)) {
+ return(NULL)
+ }
stringr::str_c(get_nhc_link(), "gis/", matches)
}
@@ -410,12 +458,13 @@ gis_windfield <- function(key, advisory = as.character()) {
#' }
#' @export
gis_wsp <- function(datetime, res = c(5, 0.5, 0.1)) {
-
- if (!grepl("[[:digit:]]{4,10}", datetime))
+ if (!grepl("[[:digit:]]{4,10}", datetime)) {
stop("`datetime` should be between 4 and 10 digits.", call. = FALSE)
+ }
- if (!(all(res %in% c(5.0, 0.5, 0.1))))
+ if (!(all(res %in% c(5.0, 0.5, 0.1)))) {
stop("`res` should be one or more of 5.0, 0.5, or 0.1.", call. = FALSE)
+ }
res <- as.character(res)
res <- stringr::str_replace(res, "^5$", "5km")
@@ -449,22 +498,3 @@ gis_wsp <- function(datetime, res = c(5, 0.5, 0.1)) {
stringr::str_c(get_nhc_link(), "gis/", links)
}
-
-#' @title shp_to_df
-#' @description Convert shapefile object to dataframe
-#' @param obj Spatial object to convert. See details.
-#' @details Takes a SpatialLinesDataFrame object or SpatialPolygonsDataFrame
-#' object and converts into a dataframe that can be plotted in ggplot2.
-#' @export
-shp_to_df <- function(obj) {
-
- if (class(obj) %in% c("SpatialLinesDataFrame", "SpatialPolygonsDataFrame")) {
- obj@data$id <- rownames(obj@data)
- obj <- dplyr::left_join(broom::tidy(obj, region = "id"),
- obj@data, by = "id") %>%
- tibble::as_tibble()
- }
-
- obj
-
-}
diff --git a/R/posest.R b/R/posest.R
index abd7ec7d..e4999081 100644
--- a/R/posest.R
+++ b/R/posest.R
@@ -25,7 +25,6 @@ get_posest <- function(links) {
#' @seealso \code{\link{get_posest}}
#' @keywords internal
posest <- function(contents) {
-
status <- scrape_header(
contents = contents,
ptn_product_title = "(?:POSITION ESTIMATE)?",
@@ -37,10 +36,9 @@ posest <- function(contents) {
key <- scrape_key(contents)
tibble::tibble(
- Status = status[,1],
- Name = status[,2],
+ Status = status[, 1],
+ Name = status[, 2],
Date = issue_date,
Contents = contents
)
-
}
diff --git a/R/prblty.R b/R/prblty.R
index 0c397618..7c17e564 100644
--- a/R/prblty.R
+++ b/R/prblty.R
@@ -29,7 +29,6 @@ get_prblty <- function(links) {
#' @seealso \code{\link{get_prblty}}
#' @keywords internal
prblty <- function(contents) {
-
status <- scrape_header(
contents = contents,
# The "SPECIAL" pattern has to be left here; moving it under
@@ -42,30 +41,33 @@ prblty <- function(contents) {
# 15.0N 43.4W 43 1 X X 44 16.8N 48.2W X 4 16 2 22
# 15.8N 45.9W 1 26 1 X 28
- ptn <- stringr::str_c("(?<=[:blank:]{3}|\n)",
- "([[:alpha:][:digit:][:punct:][:blank:]]{17})", # Location
- "[:blank:]+", # Delimiter
- "([:digit:]{1,2}|X)", # A
- "[:blank:]+", # Delimiter
- "([:digit:]{1,2}|X)", # B
- "[:blank:]+", # Delimiter
- "([:digit:]{1,2}|X)", # C
- "[:blank:]+", # Delimiter
- "([:digit:]{1,2}|X)", # D
- "[:blank:]+", # Delimiter
- "([:digit:]{1,2}|X)") # E
+ ptn <- stringr::str_c(
+ "(?<=[:blank:]{3}|\n)",
+ "([[:alpha:][:digit:][:punct:][:blank:]]{17})", # Location
+ "[:blank:]+", # Delimiter
+ "([:digit:]{1,2}|X)", # A
+ "[:blank:]+", # Delimiter
+ "([:digit:]{1,2}|X)", # B
+ "[:blank:]+", # Delimiter
+ "([:digit:]{1,2}|X)", # C
+ "[:blank:]+", # Delimiter
+ "([:digit:]{1,2}|X)", # D
+ "[:blank:]+", # Delimiter
+ "([:digit:]{1,2}|X)"
+ ) # E
prblty <-
contents %>%
stringr::str_match_all(ptn) %>%
purrr::map(tibble::as_tibble) %>%
purrr::map(
- rlang::set_names, nm = c("X1", "Location", "A", "B", "C", "D", "E")
+ rlang::set_names,
+ nm = c("X1", "Location", "A", "B", "C", "D", "E")
) %>%
- purrr::map2(status[,1], ~tibble::add_column(.x, Status = .y, .before = 1)) %>%
- purrr::map2(status[,2], ~tibble::add_column(.x, Name = .y, .after = 1)) %>%
- purrr::map2(status[,3], ~tibble::add_column(.x, Adv = .y, .after = 2)) %>%
- purrr::map2(issue_date, ~tibble::add_column(.x, Date = .y, .after = 3)) %>%
+ purrr::map2(status[, 1], ~ tibble::add_column(.x, Status = .y, .before = 1)) %>%
+ purrr::map2(status[, 2], ~ tibble::add_column(.x, Name = .y, .after = 1)) %>%
+ purrr::map2(status[, 3], ~ tibble::add_column(.x, Adv = .y, .after = 2)) %>%
+ purrr::map2(issue_date, ~ tibble::add_column(.x, Date = .y, .after = 3)) %>%
purrr::map_df(tibble::as_tibble) %>%
dplyr::select(-c("X1")) %>%
# Trim whitespace
@@ -86,5 +88,4 @@ prblty <- function(contents) {
.vars = c(6:10),
.funs = "as.numeric"
)
-
}
diff --git a/R/public.R b/R/public.R
index b72beb60..e6c6ab66 100644
--- a/R/public.R
+++ b/R/public.R
@@ -25,7 +25,6 @@ get_public <- function(links) {
#' @seealso \code{\link{get_public}}
#' @keywords internal
public <- function(contents) {
-
status <- scrape_header(
contents = contents,
# The "SPECIAL" pattern has to be left here; moving it under
@@ -38,12 +37,11 @@ public <- function(contents) {
key <- scrape_key(contents)
tibble::tibble(
- Status = status[,1],
- Name = status[,2],
- Adv = status[,3],
+ Status = status[, 1],
+ Name = status[, 2],
+ Adv = status[, 3],
Date = issue_date,
Key = key,
Contents = contents
)
-
}
diff --git a/R/scrapers.R b/R/scrapers.R
index 7f3aa6db..4f0693de 100644
--- a/R/scrapers.R
+++ b/R/scrapers.R
@@ -4,9 +4,7 @@
#' @seealso \code{\link{scrape_header}}
#' @keywords internal
scrape_date <- function(header) {
-
maketime <- function(h, m, p) {
-
h <- as.numeric(h)
m <- as.numeric(m)
@@ -22,7 +20,6 @@ scrape_date <- function(header) {
m <- stringr::str_pad(m, 2, side = "left", pad = "0")
stringr::str_c(h, m, sep = ":")
-
}
# The time value in the headers can vary depending on the product. In
@@ -44,76 +41,97 @@ scrape_date <- function(header) {
any(
stringr::str_count(
header,
- pattern = stringr::str_c("\nNOON [:upper:]{3} [:upper:]{3} ",
- "[:upper:]{3} [:digit:]{2} ",
- "[:digit:]{4}\n"))))
-
+ pattern = stringr::str_c(
+ "\nNOON [:upper:]{3} [:upper:]{3} ",
+ "[:upper:]{3} [:digit:]{2} ",
+ "[:digit:]{4}\n"
+ )
+ )
+ )) {
header <- stringr::str_replace(
header,
- pattern = stringr::str_c("\n(NOON)",
- "( [:upper:]{3}",
- " [:upper:]{3} ",
- "[:upper:]{3} ",
- "[:digit:]{2} ",
- "[:digit:]{4})\n"),
- "\n12 PM\\2\n")
+ pattern = stringr::str_c(
+ "\n(NOON)",
+ "( [:upper:]{3}",
+ " [:upper:]{3} ",
+ "[:upper:]{3} ",
+ "[:digit:]{2} ",
+ "[:digit:]{4})\n"
+ ),
+ "\n12 PM\\2\n"
+ )
+ }
# Same thing for "MIDNIGHT"
if (
any(
stringr::str_count(
header,
- pattern = stringr::str_c("\nMIDNIGHT",
- " [:upper:]{3} [:upper:]{3} ",
- "[:upper:]{3} [:digit:]{2} ",
- "[:digit:]{4}\n"))))
-
+ pattern = stringr::str_c(
+ "\nMIDNIGHT",
+ " [:upper:]{3} [:upper:]{3} ",
+ "[:upper:]{3} [:digit:]{2} ",
+ "[:digit:]{4}\n"
+ )
+ )
+ )) {
header <- stringr::str_replace(
header,
- pattern = stringr::str_c("\n(MIDNIGHT)( ",
- "[:upper:]{3}",
- " [:upper:]{3} ",
- "[:upper:]{3} ",
- "[:digit:]{2} ",
- "[:digit:]{4})\n"),
- "\n12 AM\\2\n")
+ pattern = stringr::str_c(
+ "\n(MIDNIGHT)( ",
+ "[:upper:]{3}",
+ " [:upper:]{3} ",
+ "[:upper:]{3} ",
+ "[:digit:]{2} ",
+ "[:digit:]{4})\n"
+ ),
+ "\n12 AM\\2\n"
+ )
+ }
# And yes there is actually an entry of 12 NOON; see AL132002 public adv 49A
if (
any(
stringr::str_count(
header,
- pattern = stringr::str_c("\n12 NOON",
- " [:upper:]{3} [:upper:]{3} ",
- "[:upper:]{3} [:digit:]{2} ",
- "[:digit:]{4}\n"))))
-
+ pattern = stringr::str_c(
+ "\n12 NOON",
+ " [:upper:]{3} [:upper:]{3} ",
+ "[:upper:]{3} [:digit:]{2} ",
+ "[:digit:]{4}\n"
+ )
+ )
+ )) {
header <- stringr::str_replace(
header,
- pattern = stringr::str_c("\n(12 NOON)( ",
- "[:upper:]{3}",
- " [:upper:]{3} ",
- "[:upper:]{3} ",
- "[:digit:]{2} ",
- "[:digit:]{4})\n"),
- "\n12 PM\\2\n")
+ pattern = stringr::str_c(
+ "\n(12 NOON)( ",
+ "[:upper:]{3}",
+ " [:upper:]{3} ",
+ "[:upper:]{3} ",
+ "[:digit:]{2} ",
+ "[:digit:]{4})\n"
+ ),
+ "\n12 PM\\2\n"
+ )
+ }
ptn <- stringr::str_c(
"(?<=(?:\n|\r))",
- "([:digit:]{1,2})", # Hour
+ "([:digit:]{1,2})", # Hour
"(?<=[:digit:]{1})([:digit:]{2})?", # Minute
- "(?:Z)?", # For forecast; Z is (UTC)
+ "(?:Z)?", # For forecast; Z is (UTC)
"[:blank:]",
"(?:AM|PM)?[:blank:]?",
- "([:alpha:]{3})*?", # Time zone, optional
+ "([:alpha:]{3})*?", # Time zone, optional
"[:blank:]?",
- "(?:[:alpha:]{3})", # Day of week, no capture
+ "(?:[:alpha:]{3})", # Day of week, no capture
"[:blank:]",
- "([:alpha:]{3})", # Month, abbreviated uppercase
+ "([:alpha:]{3})", # Month, abbreviated uppercase
"[:blank:]",
- "([:digit:]{1,2})", # Date
+ "([:digit:]{1,2})", # Date
"[:blank:]",
- "([:digit:]{4})", # Year
+ "([:digit:]{4})", # Year
"[[:blank:]\n\r]*"
)
@@ -123,23 +141,27 @@ scrape_date <- function(header) {
period <- stringr::str_match(datetime.extracted, "[:blank:](AM|PM)[:blank:]")
# Convert time values to 24-hour format, UTC
- t <- maketime(datetime.extracted[,2], # Hour
- datetime.extracted[,3], # Minute
- period[,2])
+ t <- maketime(
+ datetime.extracted[, 2], # Hour
+ datetime.extracted[, 3], # Minute
+ period[, 2]
+ )
# Format date
- d <- as.Date(stringr::str_c(datetime.extracted[,5], # Month, abbreviated
- datetime.extracted[,6], # Date, w/wo leading 0
- datetime.extracted[,7], # Year, four-digit format
- sep = "-"),
- format = "%b-%d-%Y")
+ d <- as.Date(stringr::str_c(datetime.extracted[, 5], # Month, abbreviated
+ datetime.extracted[, 6], # Date, w/wo leading 0
+ datetime.extracted[, 7], # Year, four-digit format
+ sep = "-"
+ ),
+ format = "%b-%d-%Y"
+ )
# If time zone is NA, make UTC. Is NA because in forecast products time is
# immeidately followed by Z which is not captured. Z is military code for
# Zulu time which is equivalent of Z.
# That should be the reason...
- tz <- datetime.extracted[,4]
+ tz <- datetime.extracted[, 4]
if (any(is.na(tz))) {
i <- which(is.na(tz))
tz[i] <- "UTC"
@@ -179,7 +201,6 @@ scrape_date <- function(header) {
# Now convert to UTC
lubridate::with_tz(dt, tzone = "UTC")
-
}
#' @title scrape_header
@@ -208,19 +229,20 @@ scrape_header <- function(contents, ptn_product_title,
# Pattern for storm names
ptn_names <- stringr::str_c("([\\w-]*?)")
- ptn_adv = "NUMBER\\s+(\\d{1,3}\\w?)"
+ ptn_adv <- "NUMBER\\s+(\\d{1,3}\\w?)"
# Combine patterns
ptn <- stringr::str_c(
- ptn_status, ptn_names, ptn_product_title, sep = "\\s"
+ ptn_status, ptn_names, ptn_product_title,
+ sep = "\\s"
)
if (advisory_number) {
- ptn <- stringr::str_c(ptn, ptn_adv, sep = "\\s")
- matches <- stringr::str_match(header, ptn)[,2:4]
+ ptn <- stringr::str_c(ptn, ptn_adv, sep = "\\s")
+ matches <- stringr::str_match(header, ptn)[, 2:4]
} else {
- matches <- stringr::str_match(header, ptn)[,2:3]
- status <- apply(stringr::str_match(header, ptn)[,2:3], 2, stringr::str_to_title)
+ matches <- stringr::str_match(header, ptn)[, 2:3]
+ status <- apply(stringr::str_match(header, ptn)[, 2:3], 2, stringr::str_to_title)
}
# String-to-title Status and Name
@@ -230,11 +252,10 @@ scrape_header <- function(contents, ptn_product_title,
matches[1:2] <- stringr::str_to_title(matches[1:2])
} else {
# Working with a matrix
- matches[,c(1:2)] <- apply(matches[,c(1:2)], 2, stringr::str_to_title)
+ matches[, c(1:2)] <- apply(matches[, c(1:2)], 2, stringr::str_to_title)
}
return(matches)
-
}
#' @title scrape_key
@@ -255,9 +276,7 @@ scrape_key <- function(header) {
"([:alnum:]{6,8})"
)
- ptn <- stringr::str_c(ptn, collapse = '')
-
- stringr::str_match(header, ptn)[,2]
+ ptn <- stringr::str_c(ptn, collapse = "")
+ stringr::str_match(header, ptn)[, 2]
}
-
diff --git a/R/tracking_chart.R b/R/tracking_chart.R
deleted file mode 100644
index 5a620052..00000000
--- a/R/tracking_chart.R
+++ /dev/null
@@ -1,137 +0,0 @@
-#' @title al_tracking_chart
-#' @description Build tracking chart centered on Atlantic Basin.
-#' @param ... Additional parameters for \link{tracking_chart} and ggplot2
-#' @seealso \code{\link{tracking_chart}}
-#' @return ggplot2 object centered on Atlantic basin.
-#' @examples
-#' \dontrun{
-#' # Build map with white land areas, thin black borders
-#' al_tracking_chart(color = "black", size = 0.1, fill = "white")
-#'
-#' # 50nm resolution, no states
-#' al_tracking_chart(res = 50, states = FALSE, color = "black", size = 0.1,
-#' fill = "white")
-#'
-#' # 50nm resolution, coastlines only
-#' al_tracking_chart(countries = FALSE, res = 50, color = "black", size = 0.1,
-#' fill = "white")
-#'
-#' # Adding and modifying with ggplot functions
-#' al_tracking_chart(color = "black", size = 0.1, fill = "white") +
-#' ggplot2::labs(x = "Lon", y = "Lat",
-#' title = "Base Atlantic Tracking Chart")
-#' }
-#' @export
-al_tracking_chart <- function(...) {
- p <- tracking_chart(...)
- p + ggplot2::coord_equal(xlim = c(-100, 0), ylim = c(0, 60))
-}
-
-#' @title ep_tracking_chart
-#' @description Build tracking chart centered on northeast Pacific Basin.
-#' @param ... Additional parameters for ggplot2
-#' @seealso \code{\link{tracking_chart}}
-#' @return ggplot2 object centered on northeast Pacific basin.
-#' @examples
-#' \dontrun{
-#' # Build map with white land areas, thin black borders
-#' ep_tracking_chart(color = "black", size = 0.1, fill = "white")
-#'
-#' # 50nm resolution, no states
-#' ep_tracking_chart(res = 50, states = FALSE, color = "black", size = 0.1,
-#' fill = "white")
-#'
-#' # 50nm resolution, coastlines only
-#' ep_tracking_chart(countries = FALSE, res = 50, color = "black", size = 0.1,
-#' fill = "white")
-#'
-#' # Adding and modifying with ggplot functions
-#' ep_tracking_chart(color = "black", size = 0.1, fill = "white") +
-#' ggplot2::labs(x = "Lon", y = "Lat",
-#' title = "Base East Pacific Tracking Chart")
-#' }
-#' @export
-ep_tracking_chart <- function(...) {
- p <- tracking_chart(...)
- p + ggplot2::coord_equal(xlim = c(-140, -80), ylim = c(0, 35))
-}
-
-#' @title tracking_chart
-#' @description Build base tracking chart using ggplot
-#' @param countries Show country borders. Default TRUE.
-#' @param states Show state boundaries. Default TRUE. Ignored if `countries` is
-#' FALSE.
-#' @param res Resolution of charts; 110 (1:110m), 50 (1:50m), 10 (1:10m).
-#' Default is low. The higher the resolution, the longer the plot takes to
-#' appear.
-#' @param ... Additional ggplot2::aes parameters
-#' @return Returns ggplot2 object that can be printed directly or have new
-#' layers added.
-#' @seealso \code{\link[ggplot2]{aes}}
-#' @examples
-#' \dontrun{
-#' # Build map with white land areas, thin black borders
-#' tracking_chart(color = "black", size = 0.1, fill = "white")
-#'
-#' # 50nm resolution, no states
-#' tracking_chart(res = 50, states = FALSE, color = "black", size = 0.1,
-#' fill = "white")
-#'
-#' # 50nm resolution, coastlines only
-#' tracking_chart(countries = FALSE, res = 50, color = "black", size = 0.1,
-#' fill = "white")
-#'
-#' # Adding and modifying with ggplot functions
-#' tracking_chart(color = "black", size = 0.1, fill = "white") +
-#' ggplot2::labs(x = "Lon", y = "Lat", title = "Base Tracking Chart")
-#' }
-#' @export
-tracking_chart <- function(countries = TRUE, states = TRUE, res = 110, ...) {
-
- # Convert to numeric just in case
- res <- as.integer(res)
-
- # Validate res
- if (!(res %in% c(110, 50, 10)))
- stop("Chart resolution must be 110, 50, 10")
-
- pkg <- "rnaturalearth"
- if (res %in% c(110, 50)) {
- pkg <- stringr::str_c(pkg, "data")
- } else {
- pkg <- stringr::str_c(pkg, "hires")
- }
-
- # A base map can be drawn off either coastlines data or countries data. If
- # countries is FALSE, return coastlines data. Otherwise, build countries w/
- # states if states is TRUE.
- if (!countries) {
- dataset <- stringr::str_c("coastline", res)
- base_map_data <- getExportedValue(ns = pkg, name = dataset)
- } else {
- dataset <- stringr::str_c("countries", res)
- base_map_data <- getExportedValue(ns = pkg, name = dataset)
- if (states) {
- if (res >= 50) {
- dataset <- stringr::str_c("states", 50)
- state_map_data <- getExportedValue(ns = pkg, name = dataset)
- } else {
- dataset <- stringr::str_c("states", res)
- state_map_data <- getExportedValue(ns = pkg, name = dataset)
- }
- }
- }
-
- p <- ggplot2::ggplot() +
- ggplot2::geom_polygon(data = base_map_data,
- ggplot2::aes(long, lat, group = group), ...) +
- ggplot2::coord_equal()
-
- if (exists("state_map_data"))
- p <- p +
- ggplot2::geom_polygon(data = state_map_data,
- ggplot2::aes(long, lat, group = group), ...)
-
- return(p)
-
-}
diff --git a/R/update.R b/R/update.R
index 0500de4a..b4d0a47d 100644
--- a/R/update.R
+++ b/R/update.R
@@ -24,7 +24,6 @@ get_update <- function(links) {
#' @seealso \code{\link{get_update}}
#' @keywords internal
update <- function(contents) {
-
status <- scrape_header(
contents = contents,
ptn_product_title = "(?:UPDATE )?",
@@ -36,11 +35,10 @@ update <- function(contents) {
key <- scrape_key(contents)
tibble::tibble(
- Status = status[,1],
- Name = status[,2],
+ Status = status[, 1],
+ Name = status[, 2],
Date = issue_date,
Key = key,
Contents = contents
)
-
}
diff --git a/R/wndprb.R b/R/wndprb.R
index 7058370d..c1c1f7b1 100644
--- a/R/wndprb.R
+++ b/R/wndprb.R
@@ -123,9 +123,10 @@ parse_stations <- function(x) {
df <- readLines(x) %>%
tibble::as_tibble() %>%
tidyr::separate(.data$value,
- c("X1", "Location", "Lat", "Lon", "X5", "X6", "X7"),
- sep = ",",
- extra = "warn") %>%
+ c("X1", "Location", "Lat", "Lon", "X5", "X6", "X7"),
+ sep = ",",
+ extra = "warn"
+ ) %>%
dplyr::arrange(.data$Location)
return(df)
}
@@ -137,7 +138,6 @@ parse_stations <- function(x) {
#' @param contents Link to a storm's specific wind probability product.
#' @keywords internal
wndprb <- function(contents) {
-
status <- scrape_header(
contents = contents,
# The "SPECIAL" pattern has to be left here; moving it under
@@ -149,51 +149,53 @@ wndprb <- function(contents) {
key <- scrape_key(contents)
- ptn <- stringr::str_c("(?<=\n)", # Look-behind
- # Location - first value must be capital letter.
- "([:upper:]{1}[[:alnum:][:blank:][:punct:]]{14})",
- # Wind
- "([[:digit:]]{2})",
- # Wind12
- "[:blank:]+([:digit:]{1,2}|X)",
- # Delim
- "[:blank:]+",
- # Wind24
- "([:digit:]{1,2}|X)",
- # Wind24 cumulative
- "+\\([:blank:]*([:digit:]{1,2}|X)\\)",
- # Delim
- "[:blank:]+",
- # Wind36
- "([:digit:]{1,2}|X)",
- # Wind36 cumulative
- "+\\([:blank:]*([:digit:]{1,2}|X)\\)",
- # Delim
- "[:blank:]+",
- # Wind48
- "([:digit:]{1,2}|X)",
- # Wind48 cumulative
- "+\\([:blank:]*([:digit:]{1,2}|X)\\)",
- # Delim
- "[:blank:]+",
- # Wind72
- "([:digit:]{1,2}|X)",
- # Wind72 cumulative
- "+\\([:blank:]*([:digit:]{1,2}|X)\\)",
- # Delim
- "[:blank:]+",
- # Wind96
- "([:digit:]{1,2}|X)",
- # Wind96 cumulative
- "+\\([:blank:]*([:digit:]{1,2}|X)\\)",
- # Delim
- "[:blank:]+",
- # Wind120
- "([:digit:]{1,2}|X)",
- # Wind120 cumulative
- "+\\([:blank:]*([:digit:]{1,2}|X)\\)",
- # End
- "[[:blank:]\n]+")
+ ptn <- stringr::str_c(
+ "(?<=\n)", # Look-behind
+ # Location - first value must be capital letter.
+ "([:upper:]{1}[[:alnum:][:blank:][:punct:]]{14})",
+ # Wind
+ "([[:digit:]]{2})",
+ # Wind12
+ "[:blank:]+([:digit:]{1,2}|X)",
+ # Delim
+ "[:blank:]+",
+ # Wind24
+ "([:digit:]{1,2}|X)",
+ # Wind24 cumulative
+ "+\\([:blank:]*([:digit:]{1,2}|X)\\)",
+ # Delim
+ "[:blank:]+",
+ # Wind36
+ "([:digit:]{1,2}|X)",
+ # Wind36 cumulative
+ "+\\([:blank:]*([:digit:]{1,2}|X)\\)",
+ # Delim
+ "[:blank:]+",
+ # Wind48
+ "([:digit:]{1,2}|X)",
+ # Wind48 cumulative
+ "+\\([:blank:]*([:digit:]{1,2}|X)\\)",
+ # Delim
+ "[:blank:]+",
+ # Wind72
+ "([:digit:]{1,2}|X)",
+ # Wind72 cumulative
+ "+\\([:blank:]*([:digit:]{1,2}|X)\\)",
+ # Delim
+ "[:blank:]+",
+ # Wind96
+ "([:digit:]{1,2}|X)",
+ # Wind96 cumulative
+ "+\\([:blank:]*([:digit:]{1,2}|X)\\)",
+ # Delim
+ "[:blank:]+",
+ # Wind120
+ "([:digit:]{1,2}|X)",
+ # Wind120 cumulative
+ "+\\([:blank:]*([:digit:]{1,2}|X)\\)",
+ # End
+ "[[:blank:]\n]+"
+ )
wndprb <-
contents %>%
@@ -201,13 +203,15 @@ wndprb <- function(contents) {
purrr::map(tibble::as_tibble, .name_repair = "minimal") %>%
purrr::map(
.f = rlang::set_names,
- nm = c("X1", "Location", "Wind", "Wind12", "Wind24", "Wind24Cum",
- "Wind36", "Wind36Cum", "Wind48", "Wind48Cum", "Wind72",
- "Wind72Cum", "Wind96", "Wind96Cum", "Wind120", "Wind120Cum")
+ nm = c(
+ "X1", "Location", "Wind", "Wind12", "Wind24", "Wind24Cum",
+ "Wind36", "Wind36Cum", "Wind48", "Wind48Cum", "Wind72",
+ "Wind72Cum", "Wind96", "Wind96Cum", "Wind120", "Wind120Cum"
+ )
) %>%
- purrr::map2(key, ~tibble::add_column(.x, Key = .y, .before = 1)) %>%
- purrr::map2(status[,3], ~tibble::add_column(.x, Adv = .y, .after = 2)) %>%
- purrr::map2(issue_date, ~tibble::add_column(.x, Date = .y, .after = 3)) %>%
+ purrr::map2(key, ~ tibble::add_column(.x, Key = .y, .before = 1)) %>%
+ purrr::map2(status[, 3], ~ tibble::add_column(.x, Adv = .y, .after = 2)) %>%
+ purrr::map2(issue_date, ~ tibble::add_column(.x, Date = .y, .after = 3)) %>%
purrr::map_df(tibble::as_tibble) %>%
dplyr::select(-c("X1")) %>%
# Trim whitespace
@@ -228,5 +232,4 @@ wndprb <- function(contents) {
.vars = c(2, 5:18),
.funs = "as.numeric"
)
-
}
diff --git a/README.Rmd b/README.Rmd
index 360bc0bd..7173f1bf 100644
--- a/README.Rmd
+++ b/README.Rmd
@@ -6,9 +6,11 @@ output: github_document
[](https://github.com/ropensci/rrricanes/tags)
[](https://github.com/ropensci/onboarding/issues/118)
[](https://cran.r-project.org/package=rrricanes)
-[](https://travis-ci.org/ropensci/rrricanes)
+[](https://travis-ci.org/ropensci/rrricanes)
[](https://ci.appveyor.com/project/timtrice/rrricanes-g4dos)
+[](https://cloud.docker.com/repository/docker/timtrice/rrricanes)
[](https://codecov.io/gh/ropensci/rrricanes)
+[](https://rstudio.cloud/project/400381)
```{r, echo = FALSE}
knitr::opts_chunk$set(
@@ -18,7 +20,9 @@ knitr::opts_chunk$set(
)
```
-# rrricanes
+# rrricanes (`r desc::desc_get_version() `)
+
+## `r desc::desc_get_field("Title")`
`rrricanes` is a R library that extracts information from [available archives](http://www.nhc.noaa.gov/archive/1998/1998archive.shtml) on past and current tropical cyclones. Currently, archives date back to 1998.
@@ -30,9 +34,7 @@ This library parses the text advisories of all tropical cyclones since 1998. Ove
I wrote this package with the goal of consolidating messy text data into well-organized formats that can easily be saved to CSV, SQL and other data formats.
-You may explore some features of the package through the [shinycanes](https://timtrice.shinyapps.io/shinycanes/) beta web application (built with R Shiny).
-
-## Advisory Products
+### Advisory Products
Generally speaking, there are five products available for tropical cyclones issued at 03:00, 09:00, 15:00 and 21:00 UTC;
@@ -54,7 +56,7 @@ These products are included in the package though they have been discontinued at
2. Position Estimates - Typically issued as a storm is threatening land but generally rare (see Hurricane Ike 2008, Key AL092008). It is generally just an update of the current location of the cyclone. After the 2011 hurricane season, this product was discontinued; Updates are now issued in their place.
-## Getting Started
+### Getting Started
Please view the vignette 'Getting Started':
@@ -64,7 +66,7 @@ vignette("getting_started", package = "rrricanes")
[Online documentation](https://timtrice.github.io/rrricanes/) is also available.
-### Prerequisites
+#### Prerequisites
`rrricanes` requires an active internet connection as data is extracted from online sources.
@@ -73,20 +75,16 @@ Linux users must also have the `libgdal-dev`, `libproj-dev` and `libxml2-dev` pa
To add `rrricanesdata`, a [package of post-scraped datasets](https://github.com/ropensci/rrricanesdata),
```r
-install.packages("rrricanesdata",
- repos = "https://timtrice.github.io/drat/",
- type = "source")
+remotes::install_github("ropensci/rrricanesdata")
```
To use high resolution tracking maps you will need to install the `rnaturalearthhires` package.
```r
-install.packages("rnaturalearthhires",
- repos = "http://packages.ropensci.org",
- type = "source")
+remotes::install_github("ropensci/rnaturalearthhires")
```
-### Installing
+#### Installing
`rrricanes` is currently only available in GitHub. It can be installed using the `devtools` package:
@@ -94,29 +92,29 @@ install.packages("rnaturalearthhires",
devtools::install_github("ropensci/rrricanes", build_vignettes = TRUE)
```
-## Built With
+### Built With
-* [R 3.3.3](https://www.r-project.org/) - The R Project for Statistical Computing
+* [R 3.5.0](https://www.r-project.org/) - The R Project for Statistical Computing
-## Contributing
+### Contributing
Please read [CONTRIBUTING.md](https://github.com/ropensci/rrricanes/blob/master/.github/CONTRIBUTING.md) for details on our code of conduct, and the process for submitting pull requests to us.
-## Versioning
+### Versioning
We use [SemVer](http://semver.org/) for versioning. For the versions available, see the [tags on this repository](https://github.com/ropensci/rrricanes/tags).
-## Authors
+### Authors
* **Tim Trice** - *Initial work* - [timtrice](https://github.com/timtrice)
See also the list of [contributors](https://github.com/ropensci/rrricanes/contributors) who participated in this project.
-## License
+### License
This project is licensed under the MIT License - see the [LICENSE.md](LICENSE.md) file for details
-## Acknowledgments
+### Acknowledgments
* [Molyneux, James](https://github.com/jimmylovestea)
* [Padgham, Mark](https://github.com/mpadge)
@@ -125,6 +123,8 @@ This project is licensed under the MIT License - see the [LICENSE.md](LICENSE.md
* [Salmon, Maëlle](https://github.com/maelle)
* [Stachelek, Joseph](https://github.com/jsta)
-## Known Data Quality Issues
+### Known Data Quality Issues
1. Hurricane Juan (AL152003), Adv 15; no status leads to improper `Status` and `Name` values in some datasets. ([#82](https://github.com/ropensci/rrricanes/issues/82))
+
+
+# rrricanes (0.2.0.6.9002)
+
+## Web scraper for Atlantic and east Pacific hurricanes and tropical storms
`rrricanes` is a R library that extracts information from [available
archives](http://www.nhc.noaa.gov/archive/1998/1998archive.shtml) on
@@ -35,11 +41,7 @@ I wrote this package with the goal of consolidating messy text data into
well-organized formats that can easily be saved to CSV, SQL and other
data formats.
-You may explore some features of the package through the
-[shinycanes](https://timtrice.shinyapps.io/shinycanes/) beta web
-application (built with R Shiny).
-
-## Advisory Products
+### Advisory Products
Generally speaking, there are five products available for tropical
cyclones issued at 03:00, 09:00, 15:00 and 21:00 UTC;
@@ -85,7 +87,7 @@ discontinued at some point:
After the 2011 hurricane season, this product was discontinued;
Updates are now issued in their place.
-## Getting Started
+### Getting Started
Please view the vignette ‘Getting Started’:
@@ -96,7 +98,7 @@ vignette("getting_started", package = "rrricanes")
[Online documentation](https://timtrice.github.io/rrricanes/) is also
available.
-### Prerequisites
+#### Prerequisites
`rrricanes` requires an active internet connection as data is extracted
from online sources.
@@ -108,21 +110,17 @@ To add `rrricanesdata`, a [package of post-scraped
datasets](https://github.com/ropensci/rrricanesdata),
``` r
-install.packages("rrricanesdata",
- repos = "https://timtrice.github.io/drat/",
- type = "source")
+remotes::install_github("ropensci/rrricanesdata")
```
To use high resolution tracking maps you will need to install the
`rnaturalearthhires` package.
``` r
-install.packages("rnaturalearthhires",
- repos = "http://packages.ropensci.org",
- type = "source")
+remotes::install_github("ropensci/rnaturalearthhires")
```
-### Installing
+#### Installing
`rrricanes` is currently only available in GitHub. It can be installed
using the `devtools` package:
@@ -131,25 +129,25 @@ using the `devtools` package:
devtools::install_github("ropensci/rrricanes", build_vignettes = TRUE)
```
-## Built With
+### Built With
- - [R 3.3.3](https://www.r-project.org/) - The R Project for
+ - [R 3.5.0](https://www.r-project.org/) - The R Project for
Statistical Computing
-## Contributing
+### Contributing
Please read
[CONTRIBUTING.md](https://github.com/ropensci/rrricanes/blob/master/.github/CONTRIBUTING.md)
for details on our code of conduct, and the process for submitting pull
requests to us.
-## Versioning
+### Versioning
We use [SemVer](http://semver.org/) for versioning. For the versions
available, see the [tags on this
repository](https://github.com/ropensci/rrricanes/tags).
-## Authors
+### Authors
- **Tim Trice** - *Initial work* -
[timtrice](https://github.com/timtrice)
@@ -158,12 +156,12 @@ See also the list of
[contributors](https://github.com/ropensci/rrricanes/contributors) who
participated in this project.
-## License
+### License
This project is licensed under the MIT License - see the
[LICENSE.md](LICENSE.md) file for details
-## Acknowledgments
+### Acknowledgments
- [Molyneux, James](https://github.com/jimmylovestea)
- [Padgham, Mark](https://github.com/mpadge)
@@ -172,8 +170,14 @@ This project is licensed under the MIT License - see the
- [Salmon, Maëlle](https://github.com/maelle)
- [Stachelek, Joseph](https://github.com/jsta)
-## Known Data Quality Issues
+### Known Data Quality Issues
1. Hurricane Juan (AL152003), Adv 15; no status leads to improper
`Status` and `Name` values in some datasets.
([\#82](https://github.com/ropensci/rrricanes/issues/82))
+
+All notable changes to this project will be documented in this file.
-The format is based on Keep a Changelog and this project adheres to Semantic Versioning.
-nm_to_sm Convert nautical miles to survey miles. (#99)tidy_adv to replace tidy_fstadv which will be removed in release 0.2.2 (#103)get_storm_list returns dataframe of all known cyclones. (#114)gis_download and gis_latest can accept parameters for rgdal::readOGR (#104).
ep_prblty_stations now returns all stations.
al_prblty_stations, cp_prblty_stations and ep_prblty_stations datasets were modified with additional columns. Changes are documented.
get_storms and get_storm_data now use asynchronous http requests to make data collection faster. (#94)load_storm_data now takes readr::read_csv parameters.Key to discus dataframes. (#80)Adv from posest. Position estimates do not have advisory numbers. (#81)scrape_adv_num to accomodate possible “INTERMEDIATE” text in Public Advisory headers. (#83)Adv from update. Updates do not have advisory numbers. (#84)Key to get_public dataframes. (#85)Key to get_update dataframes. (#86)get_fstadv. Hrs 48 and 72 hours only have 34 and 50kt wind fields. Hrs 96 and 120 have none. (#89)knots_to_mph, mb_to_in, status_abbr_to_str, get_discus, get_fstadv, tidy_fstadv, tidy_wr, tidy_fcst and tidy_fcst_wr.gis_advisory, gis_breakpoints, gis_latest, gis_outlook, gis_prob_storm_surge, gis_windfield and gis_wsp added. These functions return one or more URLs to datasets that can be downloaded with gis_download.shp_to_df added to convert lines and polygons spatial dataframes to dataframes. Points dataframes can be converted using tibble::as_dataframe (target the @data object).load_storm_data now returns full datasets from the rrricanesdata repo including tidied fstadv data. See documentation for notes on other products. (#76)al_prblty_stations, cp_prblty_stations and ep_prblty_stations may be removed on a future release. (#46)get_fstadv, get_prblty, get_wndprb, tidy_fstadv, tidy_wr, tidy_fcst and tidy_fcst_wr.tracking_chart() for a base world plot. al_tracking_chart() for chart centered on Atlantic basin. ep_tracking_chart() for chart centered on northeast Pacific.load_storm_data() helps get datasets that have already been scraped and processed. Designed to make it more efficient to get data faster.status_abbr_to_str converts storm status abbreviations (i.e., TD, TS, HU) to string.saffir returns Saffir-Simpson classification of tropical cyclones; abbreviated.twoal and twoep for Atlantic and east Pacific tropical weather outlooks.rrricanes.http_timeout and rrricanes.http_attempts to give user more control over failures.get_storm_data now takes link as first parameter for chaining. Returns a list of dataframes for each product.tidy_fstadv, tidy_wr, tidy_fcst and tidy_fcst_wr have been added to replaced now-removed fstadv_split().get_storms on some Linux distros which generated xpath_element fun error. (#67)get_storm_data. Issue similar to #67. (#68)gis_wsp. Call in rvest::html_nodes generated “xpath_attrib” error. Add test for gis_wsp. (#70)al_prblty_stations Get list of locations for wind speed probabilities in Atlantic basin.cp_prblty_stations Get list of locations for wind speed probabilities in central Pacific basin.fstadv_split split dataframe returned from fstadv() to four narrow dataframes.get_discus get storm discussions from a storm’s archive page.get_fstadv get forecast/advisory products from a storm’s archive page.get_nhc_link returns link to NHC homepageget_posest get position estimates from a storm’s archive page.get_prblty get strike probabilities from a storm’s archive page.get_products get links to all products for a storm.get_public get public advisory statements from a storm’s archive page.get_storms get a list for storms from a year’s archive page.get_storm_data get one or multiple products for a stormget_update get updates from a storm’s archive page.get_wndprb get wind speed probabilities from a storm’s archive page.knots_to_mph Convert values from knots to mph (for wind and gust values).mb_to_in convert barometric pressure from millibars to inches.wndprb Access a specific wind speed probability for a storm.When contributing to this repository, please first discuss the change you wish to make via issue, email, or any other method with the owners of this repository before making a change.
-Please note we have a code of conduct, please follow it in all your interactions with the project.
-In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
-Examples of behavior that contributes to creating a positive environment include:
-Examples of unacceptable behavior by participants include:
-Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
-Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
-This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
-Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at tim.trice@gmail.com. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
-Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project’s leadership.
-This Code of Conduct is adapted from the Contributor Covenant, version 1.4, available at http://contributor-covenant.org/version/1/4
-YEAR: 2017 -COPYRIGHT HOLDER: Tim Trice - -The MIT License (MIT) - -Copyright (c) 2017 Tim Trice - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -- -
vignettes/accumulated_cyclone_energy.Rmd
- accumulated_cyclone_energy.Rmdlibrary(dplyr)
-library(ggplot2)
-library(HURDAT)
-library(lubridate)
-library(readr)
-library(rrricanes)
-library(rrricanesdata)ACE or Accumulated Cyclone Energy is a method of measuring energy of a cyclone or for an entire season. It is calculated by the formula
-\[ \text{ACE} = 10^{-4}\sum{v^2_\text{max}} \]
-where \(v_\text{max}\) is the wind speed in knots. Values may only be used when a storm is a tropical system with winds of at least 35 knots. Additionally, only six-hour intervals are used.
-To calculate ACE you would want to use the fstadv dataset and apply the following rules:
Status is Tropical Storm or Hurricane.Wind is not NAKey
-Wind
-fstadv <- fstadv %>%
- filter(hour(Date) %in% c(3, 9, 15, 21),
- Status %in% c("Tropical Storm", "Hurricane"),
- !is.na(Wind)) %>%
- group_by(Key) %>%
- select(Name, Wind)## Adding missing grouping variables: `Key`
-Now let’s summarise our dataset with new variable ACE.
fstadv %>%
- summarise(Name = last(Name),
- ACE = sum(Wind^2) * 1e-04) %>%
- arrange(desc(ACE)) %>%
- top_n(10)## Selecting by ACE
-## # A tibble: 10 x 3
-## Key Name ACE
-## <chr> <chr> <dbl>
-## 1 AL092004 Ivan 69.9
-## 2 AL112017 Irma 66.6
-## 3 AL132003 Isabel 62.5
-## 4 AL142016 Matthew 48.0
-## 5 AL062004 Frances 46.9
-## 6 AL152017 Maria 44.6
-## 7 AL091999 Gert 44.0
-## 8 AL112010 Igor 42.9
-## 9 AL102003 Fabian 42.6
-## 10 EP071999 Dora 42.2
-This matches somewhat well with Wikipedia and other sources. But, you may notice we’re missing some storms. rrricanes currently only holds data back to 1998; this data is considered “real-time”.
A companion package, HURDAT is available in CRAN that has data for all cyclones dating back as far as 1851. This package has less data than rrricanes. But, as it is based on a post-storm reanalysis project, the data is more accurate.
Let’s revisit the top 10 using HURDAT:
AL %>%
- filter(hour(DateTime) %in% c(0, 6, 12, 18),
- Status %in% c("TS", "HU"),
- !is.na(Wind)) %>%
- group_by(Key) %>%
- summarise(Name = last(Name),
- ACE = sum(Wind^2) * 1e-04) %>%
- arrange(desc(ACE)) %>%
- top_n(10)## Selecting by ACE
-## # A tibble: 10 x 3
-## Key Name ACE
-## <chr> <chr> <dbl>
-## 1 AL031899 UNNAMED 73.6
-## 2 AL092004 IVAN 71.5
-## 3 AL112017 IRMA 64.9
-## 4 AL091893 UNNAMED 63.5
-## 5 AL132003 ISABEL 63.3
-## 6 AL041926 UNNAMED 60.9
-## 7 AL141932 UNNAMED 59.8
-## 8 AL041906 UNNAMED 56.0
-## 9 AL041957 CARRIE 55.8
-## 10 AL091966 INEZ 54.6
-A couple of things to notice here:
-HURDAT, the common times used are 00:00, 06:00, 12:00 and 18:00 UTCACE is slightly higher and that could be for a number of reasons. For example, on re-analysis the Hurricane Research Division may have determined a cyclone was actually tropical (shown in HURDAT) when initially it was believed to be extratropical (as shown in rrricanes). Or, and more likely, they determined through additional data that a storm was actually stronger than originally though.
You can also calculate ACE for a season. Instead of grouping by Key we group by Year. I’ll stick with HURDAT in this example.
(df <- AL %>%
- mutate(Year = year(DateTime)) %>%
- filter(hour(DateTime) %in% c(0, 6, 12, 18),
- Status %in% c("TS", "HU"),
- !is.na(Wind)) %>%
- group_by(Year) %>%
- summarise(ACE = sum(Wind^2) * 1e-04) %>%
- arrange(desc(ACE))) %>%
- top_n(10)## Selecting by ACE
-## # A tibble: 10 x 2
-## Year ACE
-## <dbl> <dbl>
-## 1 1933 259.
-## 2 2005 246.
-## 3 1893 231.
-## 4 1926 230.
-## 5 1995 228.
-## 6 2004 226.
-## 7 2017 225.
-## 8 1950 211.
-## 9 1961 205.
-## 10 1998 182.
-This also matches relatively well with that on Wikipedia and other sources.
- -
It would certainly seem that tropical cyclone activity ebbs and flows over time.
-vignettes/forecast_advisory.Rmd
- forecast_advisory.Rmd## OGR data source with driver: ESRI Shapefile
-## Source: "/tmp/Rtmpo0A76k", layer: "al092008.042_5day_lin"
-## with 2 features
-## It has 9 fields
-## OGR data source with driver: ESRI Shapefile
-## Source: "/tmp/Rtmpo0A76k", layer: "al092008.042_5day_pgn"
-## with 2 features
-## It has 9 fields
-## OGR data source with driver: ESRI Shapefile
-## Source: "/tmp/Rtmpo0A76k", layer: "al092008.042_5day_pts"
-## with 13 features
-## It has 20 fields
-## OGR data source with driver: ESRI Shapefile
-## Source: "/tmp/Rtmpo0A76k", layer: "al092008.042_ww_wwlin"
-## with 5 features
-## It has 10 fields
-Get bounding box of the forecast polygon.
- -Generate a base plot of the Atlantic ocean.
- -## Regions defined for each Polygons
-## Regions defined for each Polygons
-## Coordinate system already present. Adding new coordinate system, which will replace the existing one.
-
I like to add a little cushion for the map inset and forecast cone data.
-lat_min <- bbox[2,1] - 5
-lat_max <- bbox[2,2] + 5
-lon_min <- bbox[1,1] - 10
-lon_max <- bbox[1,2] + 10Build a thin tracking map for the inset.
-bp_inset <- ggplotGrob(bp +
- geom_rect(mapping = aes(xmin = lon_min, xmax = lon_max,
- ymin = lat_min, ymax = lat_max),
- color = "red", alpha = 0) +
- theme_bw() +
- theme(axis.title = element_blank(),
- axis.ticks = element_blank(),
- axis.text.x = element_blank(),
- axis.text.y = element_blank(),
- plot.margin = margin(0, 0, 0, 0, "pt")))Modify original bp zoomed in on our area of interest.
(bp <- bp +
- coord_equal(xlim = c(lon_min, lon_max),
- ylim = c(lat_min, lat_max)) +
- scale_x_continuous(expand = c(0, 0)) +
- scale_y_continuous(expand = c(0, 0)) +
- labs(x = "Lon",
- y = "Lat",
- caption = sprintf("rrricanes %s", packageVersion("rrricanes"))))## Coordinate system already present. Adding new coordinate system, which will replace the existing one.
-
Combine bp and bp_inset to finalize initial base plot. bp will be a base plot without the inset. bpi will have the inset.
(bpi <- bp + annotation_custom(grob = bp_inset, xmin = lon_max - 5,
- xmax = lon_max - 1, ymin = -Inf,
- ymax = lat_min + 5))
Lines and Polygons spatial dataframes can be helpfully converted using shp_to_df. The original spatial dataframes can be plotted directly in ggplot2 but, to my understanding, access to the other variables are not available.
# Convert object SpatialLinesDataframe to dataframe
-shp_storm_lin <- shp_to_df(gis_adv$al092008.042_5day_lin)## Warning in bind_rows_(x, .id): Unequal factor levels: coercing to character
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): Unequal factor levels: coercing to character
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-# Convert object SpatialPolygonsDataframe to dataframe
-shp_storm_pgn <- shp_to_df(gis_adv$al092008.042_5day_pgn)## Warning in bind_rows_(x, .id): Unequal factor levels: coercing to character
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-Points dataframes can just be converted with tibble::as_data_frame.
# Convert object SpatialPointsDataframe to dataframe
-shp_storm_pts <- as_data_frame(gis_adv$al092008.042_5day_pts)## Warning: `as_data_frame()` is deprecated, use `as_tibble()` (but mind the new semantics).
-## This warning is displayed once per session.
-Modify shp_storm_pts$DVLBL with full strings and ordered factor.
shp_storm_pts$DVLBL <- factor(shp_storm_pts$DVLBL,
- levels = c("D", "S", "H"),
- labels = c("Tropical Depression",
- "Tropical Storm",
- "Hurricane"))Same with shp_storm_pts$TCWW:
shp_storm_ww$TCWW <- factor(shp_storm_ww$TCWW,
- levels = c("TWA", "TWR", "HWA", "HWR"),
- labels = c("Tropical Storm Watch",
- "Tropical Storm Warning",
- "Hurricane Watch",
- "Hurricane Warning"))bpi + geom_polygon(data = shp_storm_pgn,
- aes(x = long, y = lat, group = group),
- alpha = 0.15, fill = "orange") +
- geom_path(data = shp_storm_lin, aes(x = long, y = lat, group = group)) +
- geom_point(data = shp_storm_pts, aes(x = LON, y = LAT, fill = DVLBL,
- shape = DVLBL, size = MAXWIND)) +
- geom_path(data = shp_storm_ww, aes(x = long, y = lat, color = TCWW,
- group = group), size = 1) +
- scale_shape_manual(values = c(21, 21, 21, 21)) +
- guides(shape = guide_legend(override.aes = list(size = 3)),
- size = guide_legend(nrow = 1)) +
- theme(legend.position = "bottom",
- legend.box = "vertical")
Very often, areas that are under a hurricane watch may also be under a tropical storm warning. The chart above does not show the hurricane watch area.
-vignettes/getting_started.Rmd
- getting_started.Rmdrrricanes is intended to give easy access to hurricane archives. It is a web-scraping tool that parses the National Hurricane Center’s (NHC) archives to get storm data. Data is available for storms dating back to 1998.
There are two basins which data is available: north Atlantic (“AL”) and northeastern Pacific (“EP”). The northeastern Pacific basin typically covers from the west coast of North America to -140° longitude (140°W).
-By default, get_storms will return all storms that have developed for the current year in both basins. If no storms have developed, an error will be generated. For this example, we’ll use 2012.
get_storm_data can be used to retrieve one or multiple products for one or more cyclones. A list of dataframes is returned.
df.al_18_2012_fstadv <- df.al_2012 %>%
- filter(Name == "Hurricane Sandy") %>%
- .$Link %>%
- get_storm_data(products = "fstadv")We can get the forecast/advisory data and wind speed probabilities at once:
-df.al_18_2012 <- df.al_2012 %>%
- filter(Name == "Hurricane Sandy") %>%
- .$Link %>%
- get_storm_data(c("fstadv", "wndprb"))df.al_18_2012 now contains two dataframes for Hurricane Sandy; fstadv and wndprb.
fstadv)The core of a storm’s dataset is located in the Forecast/Advisory product, fstadv. This product contains current location, forecast position, movement and structural details of the cyclone.
To access only this product, we can use get_fstadv:
df.al_18_2012_fstadv <- df.al_2012 %>%
- filter(Name == "Hurricane Sandy") %>%
- .$Link %>%
- get_fstadv()As you may have noticed above, the dataframe is very wide at 149 variables. There are four groups of variables in this dataset: current details, current wind radii, forecast positions, and forecast wind radii.
-Let’s look at an example of the current details.
- -## Classes 'tbl_df', 'tbl' and 'data.frame': 31 obs. of 18 variables:
-## $ Status : chr "Tropical Depression" "Tropical Storm" "Tropical Storm" "Tropical Storm" ...
-## $ Name : chr "Eighteen" "Sandy" "Sandy" "Sandy" ...
-## $ Adv : num 1 2 3 4 5 6 7 8 9 10 ...
-## $ Date : POSIXct, format: "2012-10-22 15:00:00" "2012-10-22 21:00:00" ...
-## $ Key : chr "AL182012" "AL182012" "AL182012" "AL182012" ...
-## $ Lat : num 13.5 12.5 12.7 13.3 13.8 14.3 15.2 16.3 17.1 18.3 ...
-## $ Lon : num -78 -78.5 -78.6 -78.6 -77.8 -77.6 -77.2 -77 -76.7 -76.6 ...
-## $ Wind : num 25 35 40 40 45 45 50 60 70 70 ...
-## $ Gust : num 35 45 50 50 55 55 60 75 85 85 ...
-## $ Pressure: num 1003 999 998 998 993 ...
-## $ PosAcc : num 45 50 25 40 30 30 20 20 20 20 ...
-## $ FwdDir : num 230 NA NA 360 20 20 15 10 15 10 ...
-## $ FwdSpeed: num 4 NA NA 3 4 5 9 12 11 12 ...
-## $ Eye : num NA NA NA NA NA NA 25 NA NA NA ...
-## $ SeasNE : num NA 60 60 70 75 90 180 180 180 180 ...
-## $ SeasSE : num NA 60 45 80 60 90 180 180 240 240 ...
-## $ SeasSW : num NA 0 0 0 0 0 0 45 0 0 ...
-## $ SeasNW : num NA 0 45 50 50 50 0 100 90 90 ...
-The most important variable in this dataset is Key. Key is a unique identifier for each storm that develops in either basin. It is formatted such as “AABBCCCC” where “AA” is the basin abbreviation (AL or EP), “BB” is the year number of the storm left-padded, and “CC” is the year of the storm.
Adv is the second-most important variable here. You’ll notice it is in character format. For regularly-scheduled advisories, advisory numbers are always numeric. However, when watches and warnings are in effect, intermediate advisories are issued which are given alpha suffixes; i.e., 1, 2, 3, 3A, 4, 4A, 4B, 5, etc.
Only the Public Advisory (public) will be issued more frequently. All other regular products (discus, fstadv, prblty, wndprb) are generally issued every six hours.
Status lists the current designation of the cyclone, i.e., Tropical Depression, Tropical Storm, etc. A Name is given once a storm crosses the threshold of Tropical Storm; that is, winds greater than 33kts.
Lat and Lon are the current position of the storm within PosAcc nautical miles. All distance measurements are in nautical miles.
Wind and Gust are current one-minute sustained wind speeds in knots (kts). You can use the function knots_to_mph to convert this. All wind speed values are in knots.
Pressure is the lowest atmospheric pressure of the cyclone either measured or estimated. It’s value is in millibars but you can use mb_to_in() to convert to inches.
FwdDir and FwdSpeed show the compass direction of the forward movement of the cyclone. NA values indicate the storm is stationary or drifting. FwdSpeed is measured in knots.
In some cases, where hurricanes have an identifiable Eye, it’s diameter in nautical miles will also be listed.
Lastly, the Seas variables will exist for a storm of at least tropical storm-strength. This is the distance from the center of circulation that 12ft seas can be found in each quadrant. The measurement is in nautical miles.
Helper function tidy_fstadv will subset this data to a narrow dataframe.
## Warning: `tidy_fstadv is deprecated and will be removed in v0.2.2
-## # A tibble: 31 x 18
-## Key Adv Date Status Name Lat Lon Wind Gust
-## <chr> <dbl> <dttm> <chr> <chr> <dbl> <dbl> <dbl> <dbl>
-## 1 AL18… 1 2012-10-22 15:00:00 Tropi… Eigh… 13.5 -78 25 35
-## 2 AL18… 2 2012-10-22 21:00:00 Tropi… Sandy 12.5 -78.5 35 45
-## 3 AL18… 3 2012-10-23 03:00:00 Tropi… Sandy 12.7 -78.6 40 50
-## 4 AL18… 4 2012-10-23 09:00:00 Tropi… Sandy 13.3 -78.6 40 50
-## 5 AL18… 5 2012-10-23 15:00:00 Tropi… Sandy 13.8 -77.8 45 55
-## 6 AL18… 6 2012-10-23 21:00:00 Tropi… Sandy 14.3 -77.6 45 55
-## 7 AL18… 7 2012-10-24 03:00:00 Tropi… Sandy 15.2 -77.2 50 60
-## 8 AL18… 8 2012-10-24 09:00:00 Tropi… Sandy 16.3 -77 60 75
-## 9 AL18… 9 2012-10-24 15:00:00 Hurri… Sandy 17.1 -76.7 70 85
-## 10 AL18… 10 2012-10-24 21:00:00 Hurri… Sandy 18.3 -76.6 70 85
-## # … with 21 more rows, and 9 more variables: Pressure <dbl>, PosAcc <dbl>,
-## # FwdDir <dbl>, FwdSpeed <dbl>, Eye <dbl>, SeasNE <dbl>, SeasSE <dbl>,
-## # SeasSW <dbl>, SeasNW <dbl>
-Any cyclone of at least tropical storm-strength will have associated wind radius values. This is the distance from the center of circulation that a specified wind speed (34kts, 50kts, 64kts) can be found in each quadrant. Measurement is in nautical miles.
- -## Classes 'tbl_df', 'tbl' and 'data.frame': 31 obs. of 12 variables:
-## $ NE64: num NA NA NA NA NA NA NA NA 20 25 ...
-## $ SE64: num NA NA NA NA NA NA NA NA 20 20 ...
-## $ SW64: num NA NA NA NA NA NA NA NA 0 0 ...
-## $ NW64: num NA NA NA NA NA NA NA NA 0 0 ...
-## $ NE50: num NA NA NA NA NA NA 0 50 50 50 ...
-## $ SE50: num NA NA NA NA NA NA 80 70 60 60 ...
-## $ SW50: num NA NA NA NA NA NA 0 0 30 40 ...
-## $ NW50: num NA NA NA NA NA NA 0 0 30 40 ...
-## $ NE34: num NA 50 50 70 70 80 90 100 110 110 ...
-## $ SE34: num NA 60 60 80 80 90 120 120 120 120 ...
-## $ SW34: num NA 0 0 0 0 0 0 45 60 70 ...
-## $ NW34: num NA 0 0 0 0 0 30 45 60 60 ...
-A helper function, tidy_wr will reorganize this data into a narrow format and tidied up. Complete wind radius values that are NA are removed for efficiency.
## # A tibble: 77 x 8
-## Key Adv Date WindField NE SE SW NW
-## <chr> <dbl> <dttm> <dbl> <dbl> <dbl> <dbl> <dbl>
-## 1 AL182012 2 2012-10-22 21:00:00 34 50 60 0 0
-## 2 AL182012 3 2012-10-23 03:00:00 34 50 60 0 0
-## 3 AL182012 4 2012-10-23 09:00:00 34 70 80 0 0
-## 4 AL182012 5 2012-10-23 15:00:00 34 70 80 0 0
-## 5 AL182012 6 2012-10-23 21:00:00 34 80 90 0 0
-## 6 AL182012 7 2012-10-24 03:00:00 34 90 120 0 30
-## 7 AL182012 7 2012-10-24 03:00:00 50 0 80 0 0
-## 8 AL182012 8 2012-10-24 09:00:00 34 100 120 45 45
-## 9 AL182012 8 2012-10-24 09:00:00 50 50 70 0 0
-## 10 AL182012 9 2012-10-24 15:00:00 34 110 120 60 60
-## # … with 67 more rows
-Most Forecast/Advisory products will have forecast data associated with it unless the storm has dissipated or is no longer tropical. There may be up to seven forecast positions. These positions are issued by 12-hour intervals through 48 hours where they are then at 24-hour intervals; 12, 24, 36, 48, 72, 96 and 120 hours.
- -Notice each variable begins with the prefix “Hrn” where n is the forecast period as noted above. Only Date, Lat, Lon, Wind, Gust and wind radius (will discuss shortly) are given for forecast periods.
-Use tidy_fcst to tidy forecast data.
## # A tibble: 216 x 8
-## Key Adv Date FcstDate Lat Lon Wind
-## <chr> <dbl> <dttm> <dttm> <dbl> <dbl> <dbl>
-## 1 AL18… 1 2012-10-22 15:00:00 2012-10-23 00:00:00 13.7 -78.3 35
-## 2 AL18… 1 2012-10-22 15:00:00 2012-10-23 12:00:00 14.3 -78.1 45
-## 3 AL18… 1 2012-10-22 15:00:00 2012-10-24 00:00:00 15.7 -77.6 55
-## 4 AL18… 1 2012-10-22 15:00:00 2012-10-24 12:00:00 17.4 -77 60
-## 5 AL18… 1 2012-10-22 15:00:00 2012-10-25 12:00:00 20.5 -76 55
-## 6 AL18… 1 2012-10-22 15:00:00 2012-10-26 12:00:00 24.5 -74.5 55
-## 7 AL18… 1 2012-10-22 15:00:00 2012-10-27 12:00:00 27 -73 50
-## 8 AL18… 2 2012-10-22 21:00:00 2012-10-23 06:00:00 13.6 -78.5 35
-## 9 AL18… 2 2012-10-22 21:00:00 2012-10-23 18:00:00 14.9 -78.3 45
-## 10 AL18… 2 2012-10-22 21:00:00 2012-10-24 06:00:00 16.4 -77.8 55
-## # … with 206 more rows, and 1 more variable: Gust <dbl>
-A note about forecast times.
- -## # A tibble: 1 x 2
-## Date Hr12FcstDate
-## <dttm> <dttm>
-## 1 2012-10-22 15:00:00 2012-10-23 00:00:00
-Notice the Date of this advisory is Oct 22 at 15:00 UTC. The Hr12FcstDate is Oct 23, 00:00 UTC. This difference, obviously, is not 12 hours. What gives? Forecast/Advisory products are issued with two “current” positions: one that is current (and provided in the dataset) and a position from three hours prior. So, in this specific advisory the text would contain the position of the storm for Oct 22, 12:00 UTC. It is from this position the forecast points are based. I do not know why.
Therefore, while officially the forecast periods are 12, 24, 36, … hours, in reality they are 9, 21, 33, … hours from the issuance time of the product.
-Some forecast positions may also contain wind radius information (only up to 72 hours).
- -Again, these variables are prepended with the prefix prefix “Hrn” where n notes the forecast period.
-tidy_fcst_wr will tidy this subset of data.
## # A tibble: 337 x 9
-## Key Adv Date FcstDate WindField NE
-## <chr> <dbl> <dttm> <dttm> <dbl> <dbl>
-## 1 AL18… 1 2012-10-22 15:00:00 2012-10-23 00:00:00 34 40
-## 2 AL18… 1 2012-10-22 15:00:00 2012-10-23 12:00:00 34 50
-## 3 AL18… 1 2012-10-22 15:00:00 2012-10-24 00:00:00 34 80
-## 4 AL18… 1 2012-10-22 15:00:00 2012-10-24 00:00:00 50 30
-## 5 AL18… 1 2012-10-22 15:00:00 2012-10-24 12:00:00 34 90
-## 6 AL18… 1 2012-10-22 15:00:00 2012-10-24 12:00:00 50 40
-## 7 AL18… 1 2012-10-22 15:00:00 2012-10-25 12:00:00 34 200
-## 8 AL18… 1 2012-10-22 15:00:00 2012-10-25 12:00:00 50 50
-## 9 AL18… 2 2012-10-22 21:00:00 2012-10-23 06:00:00 34 50
-## 10 AL18… 2 2012-10-22 21:00:00 2012-10-23 18:00:00 34 50
-## # … with 327 more rows, and 3 more variables: SE <dbl>, SW <dbl>, NW <dbl>
-Please see the National Hurricane Center’s website for more information on understanding the Forecast/Advisory product.
-prblty)Strike probabilities were discontinued after the 2005 hurricane season (replaced by Wind Speed Probabilities; wndprb). For this example, we’ll look at Hurricane Katrina. For this we use the function get_prblty.
df.al_12_2005_prblty <- get_storms(year = 2005, basin = "AL") %>%
- filter(Name == "Hurricane Katrina") %>%
- .$Link %>%
- get_prblty()## Classes 'tbl_df', 'tbl' and 'data.frame': 937 obs. of 10 variables:
-## $ Status : chr "Tropical Depression" "Tropical Depression" "Tropical Depression" "Tropical Depression" ...
-## $ Name : chr "Twelve" "Twelve" "Twelve" "Twelve" ...
-## $ Adv : chr "1" "1" "1" "1" ...
-## $ Date : POSIXct, format: "2005-08-23 21:00:00" "2005-08-23 21:00:00" ...
-## $ Location: chr "25.0N 77.7W" "JACKSONVILLE FL" "25.7N 78.5W" "SAVANNAH GA" ...
-## $ A : num 50 0 36 0 19 0 0 0 0 0 ...
-## $ B : num 0 0 0 0 6 0 1 0 0 5 ...
-## $ C : num 0 2 0 0 1 0 0 0 0 3 ...
-## $ D : num 0 9 1 6 1 3 3 2 2 5 ...
-## $ E : num 50 11 37 6 27 3 4 2 2 13 ...
-This dataframe contains the possibility of a cyclone passing within 65 nautical miles of Location. The variables A, B, C, D, and E are as they appear in the products and were left as-is to avoid confusion. They’re definition is as follows:
A - current through 12 hours.B - within the next 12-24 hoursC - within the next 24-36 hoursD - within the next 36-48 hoursE - Total probability from current through 48 hours.Many values in the text product may be “X” for less than 1% chance of a strike. These values are converted to 0 as the fields are numeric.
-The strike probability products did not contain Key which is the unique identifier for every cyclone. So the best way to do any joins will be by Name, Adv and Date.
Strike Probabilities may not exist for most Pacific cyclones.
-wndprb)df.al_18_2012_wndprb <- df.al_2012 %>%
- filter(Name == "Hurricane Sandy") %>%
- .$Link %>%
- get_wndprb()## Classes 'tbl_df', 'tbl' and 'data.frame': 2227 obs. of 18 variables:
-## $ Key : chr "AL182012" "AL182012" "AL182012" "AL182012" ...
-## $ Adv : num 1 1 1 1 1 1 1 1 1 1 ...
-## $ Date : POSIXct, format: "2012-10-22 15:00:00" "2012-10-22 15:00:00" ...
-## $ Location : chr "FT PIERCE FL" "W PALM BEACH" "MIAMI FL" "MARATHON FL" ...
-## $ Wind : num 34 34 34 34 34 34 34 50 64 34 ...
-## $ Wind12 : num 0 0 0 0 0 0 0 0 0 0 ...
-## $ Wind24 : num 0 0 0 0 1 0 0 0 0 0 ...
-## $ Wind24Cum : num 0 0 0 0 1 0 0 0 0 0 ...
-## $ Wind36 : num 0 0 0 0 1 0 0 0 0 0 ...
-## $ Wind36Cum : num 0 0 0 0 2 0 0 0 0 0 ...
-## $ Wind48 : num 0 0 0 0 1 0 0 0 0 0 ...
-## $ Wind48Cum : num 0 0 0 0 3 0 0 0 0 0 ...
-## $ Wind72 : num 0 0 0 0 0 0 3 0 0 5 ...
-## $ Wind72Cum : num 0 0 0 0 3 0 3 0 0 5 ...
-## $ Wind96 : num 1 2 3 2 0 5 10 3 1 12 ...
-## $ Wind96Cum : num 1 2 3 2 3 5 13 3 1 17 ...
-## $ Wind120 : num 2 2 1 1 0 3 5 2 0 3 ...
-## $ Wind120Cum: num 3 4 4 3 3 8 18 5 1 20 ...
-Wind Speed Probabilities are a bit more advanced than their predecessor. The Wind variable is for 34kt, 50kt and 64kt winds expected within a specific time period.
Each consecutive variable is within a specific time-frame (12, 24, 36, 48, 72, 96 and 120 hours) for both that time frame and cumulative.
-For example, Wind24 is the chance of Wind between 12-24 hours. Wind24Cum is the cumulative probability from Date through 24 hours.
As with strike probabilities, an “X” in the original text product meant less than 0.5% chance for the specified wind in the specified time period. “X” has been replaced by 0 in this package.
-Wind Speed Probabilities may not exist for most Pacific cyclones.
-See Tropical Cyclone Wind Speed Probabilities Products for more information.
-Other products are available:
-get_public for Public Advisory statements. Think general information for the public audience. May not exist for some Pacific cyclones. Additionally, when watches and warnings are issued, these are issued every 3 hours (and, in some cases, every two).
get_discus for Storm Discussions. These are more technical statements on the structure of a storm, forecast model tendencies and satellite presentation.
get_update These are brief update statements when something considerable has changed in the cyclone or if the cyclone is making landfall.
get_posest. Position estimates are generally issued when a storm is making landfall and may be issued hourly.
Hurricane Ike, 2008, has both updates and position estimates.
-At this time none of these products are parsed. Only the content of the product is returned.
-Most storms will contain a variation of GIS datasets that can be plotted with ggplot2. The helper functions for this have the prefix ‘gis’.
All products are experimental and there maybe fluctuations particularly in current datasets.
-In general, datasets are available for storms dated back to 1998. However, products such as Wind Speed Probabilities only go back to 1999.
-Some datasets require the use of the storm key and an optional advisory. Other products require a datetime value and cannot be isolated by storm key or advisory. The datetime values are not based on the issue time of the advisory, but rather three hours prior. For example, if you are seeking a dataset where the forecast/advisory was issued at 9:00AM UTC, you will want the dataset for 6:00AM UTC. This will be explained a little further below.
-There are three functions available to help you plot GIS data; tracking_chart, al_tracking_chart and ep_tracking_chart. al_tracking_chart and ep_tracking_chart are just helpers centered on the Atlantic and northeast Pacific ocean, respectively.
## function (countries = TRUE, states = TRUE, res = 110, ...)
-## NULL
-The countries and states parameters are TRUE by default. This means a basic call to tracking_chart will return a map with country and state borders. The res parameter is resolution; one of 110, 50 or 10 nautical miles. Resolutions 110nm and 50nm can be used immediately. To use lower resolution you must install the rnaturalearthdatahires package from ropensci:
tracking_chart will print a basic tracking chart (a map of the planet).
## Regions defined for each Polygons
-## Regions defined for each Polygons
-
You can pass typical aes parameters to refine the color and fill of the plot; remember the tracking chart is a ggplot object.
## Regions defined for each Polygons
-## Regions defined for each Polygons
-
You may choose to only show coastline data instead. In this case, just set the countries parameter to FALSE.
- -
For the purposes of this vignette we’ll focus on Atlantic storms.
- -## Regions defined for each Polygons
-## Regions defined for each Polygons
-## Coordinate system already present. Adding new coordinate system, which will replace the existing one.
-
The res parameter defines the resolution of the chart presented. Options are in 110nm, 50nm and 10nm. The lower the resolution the longer the chart takes to be built.
States cannot be drawn on resolution greater than 50nm.
-There are several datasets that are published for active cyclones. The following functions are designed to return the URL to those datasets:
-gis_advisorygis_prob_storm_surgegis_windfieldgis_latest## [1] "https://www.nhc.noaa.gov/gis/forecast/archive/al182012_5day_018.zip"
-
-
-## [1] "al182012.018_5day_lin" "al182012.018_5day_pgn" "al182012.018_5day_pts"
-## [4] "al182012.018_ww_wwlin"
-For this particular storm and advisory, included are the base line, point and polygon datasets along with a dataset for watches and warnings. The objects returned are spatial dataframes contained within the list of dataframes, df.gis_adv.
## Formal class 'SpatialLinesDataFrame' [package "sp"] with 4 slots
-## ..@ data :'data.frame': 2 obs. of 7 variables:
-## .. ..$ STORMNAME: chr [1:2] "SANDY" "SANDY"
-## .. ..$ STORMTYPE: chr [1:2] "HU" "HU"
-## .. ..$ ADVDATE : chr [1:2] "121026/2100" "121026/2100"
-## .. ..$ ADVISNUM : chr [1:2] "18" "18"
-## .. ..$ STORMNUM : num [1:2] 18 18
-## .. ..$ FCSTPRD : num [1:2] 72 120
-## .. ..$ BASIN : chr [1:2] "al" "al"
-## ..@ lines :List of 2
-## .. ..$ :Formal class 'Lines' [package "sp"] with 2 slots
-## .. .. .. ..@ Lines:List of 1
-## .. .. .. .. ..$ :Formal class 'Line' [package "sp"] with 1 slot
-## .. .. .. .. .. .. ..@ coords: num [1:6, 1:2] -77.1 -77 -76.1 -74.3 -72.6 ...
-## .. .. .. ..@ ID : chr "0"
-## .. ..$ :Formal class 'Lines' [package "sp"] with 2 slots
-## .. .. .. ..@ Lines:List of 1
-## .. .. .. .. ..$ :Formal class 'Line' [package "sp"] with 1 slot
-## .. .. .. .. .. .. ..@ coords: num [1:8, 1:2] -77.1 -77 -76.1 -74.3 -72.6 ...
-## .. .. .. ..@ ID : chr "1"
-## ..@ bbox : num [1:2, 1:2] -77.1 27.3 -71.5 41
-## .. ..- attr(*, "dimnames")=List of 2
-## .. .. ..$ : chr [1:2] "x" "y"
-## .. .. ..$ : chr [1:2] "min" "max"
-## ..@ proj4string:Formal class 'CRS' [package "sp"] with 1 slot
-## .. .. ..@ projargs: chr "+proj=longlat +a=6371200 +b=6371200 +no_defs"
-As we’re dealing with a SpatialLinesDataFrame which needs to be modified, you can use the helper function shp_to_df for plotting.
## Warning in bind_rows_(x, .id): Unequal factor levels: coercing to character
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-
There are two groups of data in the set: one for 72-hour forecast period and one for 120-hour. Grouping by FCSTPRD will show the forecast track correctly.
There is a pretty wide field of view on the map above. You can use sp::bbox to “zoom in” on the map.
## min max
-## x -77.1 -71.5
-## y 27.3 41.0
-(p2 <- p + geom_path(data = fcst_line, aes(long, lat, group = FCSTPRD)) +
- coord_equal(xlim = c(bb[1,1] - 5, bb[1,2] + 5),
- ylim = c(bb[2,1] - 5, bb[2,2] + 5)))## Coordinate system already present. Adding new coordinate system, which will replace the existing one.
-
Forecast cone data is contained in the polygon dataset. To deal with this dataset you can use the shp_to_df function again or take the slightly longer way:
fcst_cone <- df.gis_adv$al182012.018_5day_pgn
-fcst_cone@data$id <- rownames(fcst_cone@data)
-fcst_cone.points <- broom::tidy(fcst_cone, region = "id")## Warning in bind_rows_(x, .id): Unequal factor levels: coercing to character
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-p3 + geom_polygon(data = fcst_cone %>% filter(FCSTPRD == 120),
- aes(long, lat, group = group, fill = factor(FCSTPRD)),
- alpha = 0.5) +
- geom_polygon(data = fcst_cone %>% filter(FCSTPRD == 72),
- aes(long, lat, group = group, fill = factor(FCSTPRD)),
- alpha = 0.5)
Note that in some GIS packages the forecast cones may be identical (though they shouldn’t be). I’ve noticed it with Hurricanes Ike and Matthew; it’s in the raw dataset.
-You can also plot watches and warnings if any are in effect for the package release time.
- -## Warning in bind_rows_(x, .id): Unequal factor levels: coercing to character
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-
In the example above you can see tropical storm warnings issued for the Bahamas, North Carolina and portions of the South Carolina and Florida coast while tropical storm watches are in effect for northern Florida and South Carolina.
-The Tropical Cyclone Storm Surge Probabilities data shows the probability, in percent, of a specified storm surge occurring during the forecast period indicated. The product is based upon an ensemble of Sea, Lake, and Overland Surge from Hurricanes (SLOSH) model runs using the National Hurricane Center (NHC) official advisory and accounts for track, size, and intensity errors based on historical errors.
- -## [1] "https://www.nhc.noaa.gov/gis/storm_surge/al142016_psurge0_2016100600.zip"
-## [2] "https://www.nhc.noaa.gov/gis/storm_surge/al142016_psurge0_2016100606.zip"
-## [3] "https://www.nhc.noaa.gov/gis/storm_surge/al142016_psurge0_2016100612.zip"
-## [4] "https://www.nhc.noaa.gov/gis/storm_surge/al142016_psurge0_2016100618.zip"
-df.gis_storm_surge <- gis_prob_storm_surge(key = "AL142016",
- products = list(psurge = 0),
- datetime = "20161006") %>%
- last() %>%
- gis_download()## Warning in bind_rows_(x, .id): Unequal factor levels: coercing to character
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-## Warning in bind_rows_(x, .id): Unequal factor levels: coercing to character
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-p + geom_path(data = prob_surge,
- aes(x = long, y = lat, group = group, color = PSurge00c),
- size = 1, alpha = 0.5) +
- coord_equal(xlim = c(bb[1,1], bb[1,2]), ylim = c(bb[2,1], bb[2,2]))## Coordinate system already present. Adding new coordinate system, which will replace the existing one.
-
Wind radii data may also be available for some cyclone advisory packages. This is the radius to which a minimum sustained wind speed may be felt from the center of circulation.
- -## [1] "https://www.nhc.noaa.gov/gis/forecast/archive/al142016_fcst_033.zip"
-
-
-## Warning in bind_rows_(x, .id): Unequal factor levels: coercing to character
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-(p4 <- p + geom_polygon(data = wf_init,
- aes(x = long, y = lat, fill = factor(RADII)), alpha = 0.5) +
- coord_equal(xlim = c(bb[1,1], bb[1,2]), ylim = c(bb[2,1], bb[2,2])))## Coordinate system already present. Adding new coordinate system, which will replace the existing one.
-
Additionally, forecast wind radii data is also generally available in some packages
- -## Warning in bind_rows_(x, .id): Unequal factor levels: coercing to character
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-p4 + geom_polygon(data = wf_fcst,
- aes(x = long, y = lat, group = group, fill = factor(RADII)),
- alpha = 0.5)
Wind Speed probabilities show the chance of experiencing a minimum-sustained winds of 34, 50 and 64 knots with a given period of time (typically, 120 hours). These products are not storm-specific but are global so other active cyclones in other basins may also appear.
- -## [1] "https://www.nhc.noaa.gov/gis/forecast/archive/2016100606_wsp_120hrhalfDeg.zip"
-df.gis_wsp <-
- gis_download(
- "https://www.nhc.noaa.gov/gis/forecast/archive/2016100606_wsp_120hrhalfDeg.zip"
- )bb <- sp::bbox(df.gis_wsp$`2016100606_wsp34knt120hr_halfDeg`)
-p +
- geom_sf(
- data = st_as_sf(df.gis_wsp$`2016100606_wsp34knt120hr_halfDeg`),
- aes(color = PWIND120)
- ) +
- coord_sf(xlim = c(bb[1,1], bb[1,2]), ylim = c(bb[2,1], bb[2,2]))## Coordinate system already present. Adding new coordinate system, which will replace the existing one.
-
Cumulative wind speed probability for >50kt winds:
-bb <- sp::bbox(df.gis_wsp$`2016100606_wsp50knt120hr_halfDeg`)
-p +
- geom_sf(
- data = st_as_sf(df.gis_wsp$`2016100606_wsp50knt120hr_halfDeg`),
- aes(color = PWIND120)
- ) +
- coord_sf(xlim = c(bb[1,1], bb[1,2]), ylim = c(bb[2,1], bb[2,2]))## Coordinate system already present. Adding new coordinate system, which will replace the existing one.
-
Cumulative probability for >64kt winds:
-bb <- sp::bbox(df.gis_wsp$`2016100606_wsp64knt120hr_halfDeg`)
-p +
- geom_sf(
- data = st_as_sf(df.gis_wsp$`2016100606_wsp64knt120hr_halfDeg`),
- aes(color = PWIND120)
- ) +
- coord_sf(xlim = c(bb[1,1], bb[1,2]), ylim = c(bb[2,1], bb[2,2]))## Coordinate system already present. Adding new coordinate system, which will replace the existing one.
-
vignettes/installing_rrricanesdata.Rmd
- installing_rrricanesdata.RmdWith rrricanes you can access current and archived advisories as-issued from the National Hurricane Center archives. rrricanesdata is a complimentary data package meant to make it faster to get most data avialable from these storms.
Installing rrricanesdata is simple:
Data in rrricanesdata will be updated on the first of every month with a cutoff date of midnight on the last day of the month. So, advisories issued at any time during the current month will not be available; you will need to use any of rrricanes get_* functions.
adv
-discus
-fcst
-fcst_wr
-fstadv
-n hoursn hoursn hoursn hoursn hoursn hoursn hoursn hoursn hoursn hoursn hoursn hoursn hoursn hoursn hoursn hoursposest
-prblty
-public
-storms
-update
-wndprb
-Wind within 12 hoursWind within 24 hoursWind within 36 hoursWind within 48 hoursWind within 72 hoursWind within 96 hoursWind within 120 hourswr
-Windfield in the northeast quadrantWindfield in the southeast quadrantWindfield in the southwest quadrantWindfield in the northwest quadrantvignettes/probabilistic_storm_surge.Rmd
- probabilistic_storm_surge.RmdCalculate the last date/time of forecast/advisory product and subtract 3 hrs
- -Wrap gis_download in safely. Not all products will exist for every storm or even every advisory.
I’m downloading the psurge products for 5 feet since there are no other storm surge products available for Ike.
dl <- purrr::safely(.f = gis_download)
-gis_surge <- gis_prob_storm_surge(key, products = list("psurge" = c(5)),
- datetime = dt) %>% dl()## OGR data source with driver: ESRI Shapefile
-## Source: "/tmp/RtmpYhM1pI", layer: "al092008_2008091112_gt5"
-## with 83 features
-## It has 2 fields
-
-Generate a base plot of the Atlantic ocean.
- -## Regions defined for each Polygons
-## Regions defined for each Polygons
-## Coordinate system already present. Adding new coordinate system, which will replace the existing one.
-Since we’re dealing with a polygon shapefile, we can get the bounding box of the dataset.
- -Add a little cushion for the map inset.
-lat_min <- bbox[2,1] - 2
-lat_max <- bbox[2,2] + 2
-lon_min <- bbox[1,1] - 4
-lon_max <- bbox[1,2] + 4Build a map inset.
-bp_inset <- ggplotGrob(bp +
- geom_rect(mapping = aes(xmin = lon_min, xmax = lon_max,
- ymin = lat_min, ymax = lat_max),
- color = "red", alpha = 0) +
- theme_bw() +
- theme(axis.title = element_blank(),
- axis.ticks = element_blank(),
- axis.text.x = element_blank(),
- axis.text.y = element_blank(),
- plot.margin = margin(0, 0, 0, 0, "pt")))Modify original bp zoomed in on our area of interest.
bp <- bp +
- coord_equal(xlim = c(lon_min, lon_max),
- ylim = c(lat_min, lat_max)) +
- scale_x_continuous(expand = c(0, 0)) +
- scale_y_continuous(expand = c(0, 0)) +
- labs(x = "Lon",
- y = "Lat",
- caption = sprintf("rrricanes %s", packageVersion("rrricanes")))## Coordinate system already present. Adding new coordinate system, which will replace the existing one.
-Combine bp and bp_inset to finalize initial base plot. bp will be a base plot without the inset. bpi will have the inset.
bpi <- bp + annotation_custom(grob = bp_inset, xmin = lon_max - 5,
- xmax = lon_max - 1, ymin = -Inf,
- ymax = lat_min + 5)Convert the SpatialPolygonsDataframe to a dataframe.
- -## Warning in bind_rows_(x, .id): Unequal factor levels: coercing to character
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-## Warning in bind_rows_(x, .id): Unequal factor levels: coercing to character
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-
-## Warning in bind_rows_(x, .id): binding character and factor vector,
-## coercing into character vector
-Probability of storm surge greater than five feet.
-bpi + geom_point(data = shp_storm_surge,
- aes(x = long, y = lat, color = ProbSurge05), size = 1) +
- theme(legend.position = "bottom",
- legend.box = "vertical") +
- labs(title = "Probabilistic Storm Surge > 5ft",
- caption = sprintf("rrricanes %s", packageVersion("rrricanes")))
vignettes/wind_pressure.Rmd
- wind_pressure.Rmdlibrary(dplyr)
-library(gganimate)
-library(ggplot2)
-library(rrricanes)
-library(rrricanesdata)
-library(tidyr)# Plot wind values
-fstadv %>% ggplot(aes(x = Date, y = Wind)) +
- geom_line() +
- geom_point(aes(color = Status), size = 3) +
- scale_y_continuous(name = "Wind (kts)") +
- theme_bw() +
- theme(legend.position = "bottom",
- legend.box = "vertical") +
- labs(title = "Wind Profile",
- caption = sprintf("rrricanes %s", packageVersion("rrricanes")))
# Plot pressure values
-fstadv %>% ggplot(aes(x = Date, y = Pressure)) +
- geom_line() +
- geom_point(aes(color = Status), size = 3) +
- scale_y_continuous(name = "Pressure (mb)") +
- theme_bw() +
- theme(legend.position = "bottom",
- legend.box = "vertical") +
- labs(title = "Pressure Profile",
- caption = sprintf("rrricanes %s", packageVersion("rrricanes")))
fstadv %>%
- mutate(WindDist = (Wind - min(Wind))/(max(Wind) - min(Wind)),
- PressDist = (Pressure - max(Pressure))/(max(Pressure) - min(Pressure))) %>%
- gather(Var, Val, WindDist, PressDist) %>%
- ggplot(aes(x = Date, y = Val, group = Var, color = Var)) +
- geom_line(size = 1) +
- scale_color_discrete(labels = c("Pressure Change", "Wind Change")) +
- theme_bw() +
- theme(legend.position = "bottom",
- legend.title = element_blank()) +
- labs(title = "Wind/Pressure Relational Change",
- subtitle = "",
- caption = sprintf("rrricanes %s", packageVersion("rrricanes")),
- y = "")
wr_animate <-
- fstadv %>%
- tidy_wr() %>%
- gather(Quadrant, Radius, NE:NW) %>%
- ggplot(
- aes(
- x = Quadrant,
- y = Radius,
- fill = factor(WindField),
- frame = Adv
- )
- ) +
- geom_bar(stat = "identity", position = "identity", width = 1) +
- guides(fill = guide_legend(title = "Wind Field")) +
- coord_polar() +
- theme_minimal() +
- theme(legend.position = "bottom") +
- labs(
- title = "Wind Radius for Advisory {frame}",
- subtitle = "Minimum sustained one-minute wind speed in knots",
- caption = sprintf("rrricanes %s", packageVersion("rrricanes")),
- y = "Radius (nm)"
- ) +
- transition_time(Date) +
- ease_aes('linear')
-
-animate(wr_animate, renderer = magick_renderer())
One of the interesting things to note about the image above; Hurricane Ike was known for it’s very large wind field (relatively speaking) which generated a larger and wider storm surge than normal for it’s classification. You can see this very well defined structure expansion between advisories 38 and 42.
-This, in part, led to the modification of the Saffir Simpson Hurricane Scale.
---the very large Hurricane Ike (with hurricane force winds extending as much as 125 mi from the center) in 2008 made landfall in Texas as a Category 2 hurricane and had peak storm surge values of about 20 ft. In contrast, tiny Hurricane Charley (with hurricane force winds extending at most 25 mi from the center) struck Florida in 2004 as a Category 4 hurricane and produced a peak storm surge of only about 7 ft. These storm surge values were substantially outside of the ranges suggested in the original scale. Thus to help reduce public confusion about the impacts associated with the various hurricane categories as well as to provide a more scientifically defensible scale, the storm surge ranges, flooding impact and central pressure statements are being removed from the scale and only peak winds are employed in this revised version – the Saffir-Simpson Hurricane Wind Scale. (Schott et al. 2012)
-
Schott, Timothy, Chris Landsea, Gene Hafele, Jeffrey Lorens, Arthur Taylor, Harvey Thurm, Bill Ward, Mark Willis, and Walt Zaleski. 2012. “The Saffir-Simpson Hurricane Wind Scale.” http://www.nhc.noaa.gov/pdf/sshws.pdf.
-vignettes/wind_speed_probabilities.Rmd
- wind_speed_probabilities.Rmd## OGR data source with driver: ESRI Shapefile
-## Source: "/tmp/RtmplTbZV0", layer: "al092008.042_5day_lin"
-## with 2 features
-## It has 9 fields
-## OGR data source with driver: ESRI Shapefile
-## Source: "/tmp/RtmplTbZV0", layer: "al092008.042_5day_pgn"
-## with 2 features
-## It has 9 fields
-## OGR data source with driver: ESRI Shapefile
-## Source: "/tmp/RtmplTbZV0", layer: "al092008.042_5day_pts"
-## with 13 features
-## It has 20 fields
-## OGR data source with driver: ESRI Shapefile
-## Source: "/tmp/RtmplTbZV0", layer: "al092008.042_ww_wwlin"
-## with 5 features
-## It has 10 fields
-Get bounding box of the forecast polygon.
- -## min max
-## x -98.10178 -80.20625
-## y 25.25667 41.78703
-Generate a base plot of the Atlantic ocean.
- -## Regions defined for each Polygons
-## Regions defined for each Polygons
-## Coordinate system already present. Adding new coordinate system, which will replace the existing one.
-
-
I like to add a little cushion for the map inset and forecast cone data.
-lat_min <- bbox[2,1] - 5
-lat_max <- bbox[2,2] + 5
-lon_min <- bbox[1,1] - 10
-lon_max <- bbox[1,2] + 10Build a thin tracking map for the inset.
-bp_inset <- ggplotGrob(bp +
- geom_rect(mapping = aes(xmin = lon_min, xmax = lon_max,
- ymin = lat_min, ymax = lat_max),
- color = "red", alpha = 0) +
- theme_bw() +
- theme(axis.title = element_blank(),
- axis.ticks = element_blank(),
- axis.text.x = element_blank(),
- axis.text.y = element_blank(),
- plot.margin = margin(0, 0, 0, 0, "pt")))Modify original bp zoomed in on our area of interest.
bp <- bp +
- coord_equal(xlim = c(lon_min, lon_max),
- ylim = c(lat_min, lat_max)) +
- scale_x_continuous(expand = c(0, 0)) +
- scale_y_continuous(expand = c(0, 0)) +
- labs(x = "Lon",
- y = "Lat",
- caption = sprintf("rrricanes %s", packageVersion("rrricanes")))## Coordinate system already present. Adding new coordinate system, which will replace the existing one.
-
-
Combine bp and bp_inset to finalize initial base plot. bp will be a base plot without the inset. bpi will have the inset.
bpi <- bp + annotation_custom(grob = bp_inset, xmin = lon_max - 5,
- xmax = lon_max - 1, ymin = -Inf,
- ymax = lat_min + 5)
-bpi
The wndprb will not have coordinates for cities. An option is al_prblty_stations. However, please note this function may become deprecated.
wndprb <-
- wndprb %>%
- left_join(al_prblty_stations(), by = "Location") %>%
- mutate_at(.vars = c("Lat", "Lon"), .funs = as.numeric)## Warning: Expected 7 pieces. Additional pieces discarded in 1 rows [90].
-Check wndprb for NA values in Lat, Lon.
## [1] TRUE
-wndprb_adv42 <- filter(wndprb, Adv == adv, Wind >= 64)
-
-bpi +
- geom_point(
- data = wndprb_adv42,
- aes(
- x = Lon,
- y = Lat,
- color = Wind120Cum,
- size = Wind120Cum
- )
- ) +
- scale_color_gradientn(colors = terrain.colors(10)) +
- guides(size = FALSE) +
- theme(
- legend.position = "bottom",
- legend.box = "vertical"
- ) +
- labs(title = "Total Probability of Wind >= 64kts within 120 Hours")
rrricanes is a R library that extracts information from available archives on past and current tropical cyclones. Currently, archives date back to 1998.
Data can be obtained for cyclones in the north Atlantic (considered the Atlantic Basin) and north-eastern Pacific (the East Pacific Basin from 140°W and eastward.
-Central Pacific data (140°W to 180°W) is included if issued by the National Hurricane Center (generally they’re issued by the Central Pacific Hurricane Center).
-This library parses the text advisories of all tropical cyclones since 1998. Over the years the formats of the text products have changed and many are loosely formatted.
-I wrote this package with the goal of consolidating messy text data into well-organized formats that can easily be saved to CSV, SQL and other data formats.
-You may explore some features of the package through the shinycanes beta web application (built with R Shiny).
-Generally speaking, there are five products available for tropical cyclones issued at 03:00, 09:00, 15:00 and 21:00 UTC;
-Storm Discussion - These are technical discussions centered on the current structure of the cyclone, satellite presentation, computer forecast model tendencies and more.
Forecast/Adivsory - This data-rich product lists the current location of the cyclone, its wind structure, forecast and forecast wind structure.
Public Advisory - These are general text statements issued for the public-at-large. Information in these products is a summary of the Forecast/Advisory product along with any watches and warnings issued, changed, or cancelled. Public Advisory products are the only regularly-scheduled product that may be issued intermittently (every three hours and, occasionally, every two hours) when watches and warnings are in effect.
Wind Speed Probabilities - These products list the probability of a minimum sustained wind speed expected in a given forecast window. This product replaces the Strike Probabilities product beginning in 2006 (see below).
Updates - Tropical Cyclone Updates may be issued at any time if a storm is an immediate threat to land or if the cyclone undergoes a significant change of strength or structure. The information in this product is general.
Discontinued Products
-These products are included in the package though they have been discontinued at some point:
-Strike Probabilities - List the probability of a tropical cyclone passing within 65 nautical miles of a location within a forecast window. Replaced in 2006 by the Wind Speed Probabilities product.
Position Estimates - Typically issued as a storm is threatening land but generally rare (see Hurricane Ike 2008, Key AL092008). It is generally just an update of the current location of the cyclone. After the 2011 hurricane season, this product was discontinued; Updates are now issued in their place.
Please view the vignette ‘Getting Started’:
- -Online documentation is also available.
-rrricanes requires an active internet connection as data is extracted from online sources.
Linux users must also have the libgdal-dev, libproj-dev and libxml2-dev packages installed.
To add rrricanesdata, a package of post-scraped datasets,
To use high resolution tracking maps you will need to install the rnaturalearthhires package.
Please read CONTRIBUTING.md for details on our code of conduct, and the process for submitting pull requests to us.
-We use SemVer for versioning. For the versions available, see the tags on this repository.
-This project is licensed under the MIT License - see the LICENSE.md file for details
-Status and Name values in some datasets. (#82)NEWS.md
- get_storms and get_storm_data have been rewritten to utilize pkg crul’s asynchronous features. This will not make much of a difference in get_storms (and may actually be slightly slower; to be explained). But the difference with get_storm_data should be very noticeable. There is a limit to hitting the NHC archives; 80 requests per 10 seconds. Both functions send 4 links through every 0.5 seconds to avoid this limit. Timeout issues should no longer occur so options rrricanes.http_attempts and rrricanes.http_timeout have been removed. The primary cause of long processing now is due to scraping, particularly with the fstadv products; the amount of data in these products and the unstructured nature of the products require a number of rules. This can probably be simplified in future releases. (#94)load_storm_data now takes readr::read_csv parameters.Key variable added to discus dataframes. Key will be NA for all cyclones >= 2005. Should not be <= 2006. (#80)Adv variable from posest dataframes. Position estimates do not have advisory numbers. (#81)Adv variable from update. Updates do not have advisory numbers. (#84)Key to get_public dataframes. (#85)Key to get_update dataframes. (#86)get_fstadv. Hrs 48 and 72 hours only have 34 and 50kt wind fields. Hrs 96 and 120 have none. (#89)gis_advisory Typically will include current and past track data, forecast track data, forecast cone (margin of error) and wind radius data.gis_breakpoints List of breakpoints typically used for watch/warning areas but is not a requirement.gis_latest Retrieves the latest GIS products for all active storms.gis_outlook Retrives the latest tropical weather outlook in shapefile format.gis_prob_storm_surge Probabilistic storm surge; a polygon dataset for psurge and esurge products with various criteria.gis_windfield Wind radius datasets.gis_wsp Wind speed probabilitiesgis_download Use this function to download the URLs returned from the above functions.shp_to_df added to convert lines and polygons spatial dataframes to dataframes. Points dataframes can be converted using tibble::as_dataframe (target the @data object).pkgdown.load_storm_data directly returns dataframes. Additionally, retrieval by basin and years removed in favor of importing complete product datasets. Additionally, documentation has been added to the website on using data.world as a third option. The difference between these two options is load_storm_data will return complete datasets. Using data.world will allow users to write custom queries to retrieve data. (#76)al_prblty_stations, cp_prblty_stations and ep_prblty_stations may be removed on a future release. (#46)rrricanes.http_sleep to control time to sleep between multiple HTTP requests.get_fstadv, get_prblty, get_wndprb, tidy_fstadv, tidy_wr, tidy_fcst and tidy_fcst_wr.tidy_fcst and tidy_fcst_wr would err if all forecast periods were not available for a cyclone. Functions now analyze dataframe to determine what forecast fields exist, then tidies based on the result. (#73)Changed name from Hurricanes to rrricanes.
get_storm_data can now be chained to other commands and returns a list of dataframes.
load_storm_data accesses pre-scraped datasets and returns requested products through the github repo rrricanesdata. This was done to make it quicker to get data. It should not be relied on to get the most immediate data for current storms. However, it should be fairly up-to-date. Original functions can be used if for some reason immediate data access is needed.
saffir returns Saffir-Simpson classification of tropical cyclones; abbreviated.
status_abbr_to_str converts storm status abbreviations (i.e., TD, TS, HU) to string.
twoal and twoep parse tropical weather outlook XML files. Gives current status, if any, of areas of interest in either basin.
tidy_fstadv, tidy_wr, tidy_fcst and tidy_fcst_wr have been added to replaced now-removed fstadv_split().rrricanes.http_timeout and rrricanes.http_attempts added to give user more control over this. Default is 3 attempts with no more than 5 permitted.get_storms on some linux distros generated xpath_element error. Corrected. (#67)get_storm_data. Replaced css parameter in rvest::html_nodes calls with xpath parameter. Some products (notably, get_prblty) do not have a “pre” tag but are text documents (not HTML). Modified scrape_contents to return full contents if “pre” tag doesn’t exist. Tested get_discus and get_public; no errors generated. (#68)Retrieve all storm’s for a given year (>=1998) and access data from a given storm’s history. Can access “current” storm position, structure details, forecast, and discussions.
-This release should be considered beta. While I’ve made every effort to ensure quality there may be an issue here or there. I will work on developing QA/QC scripts as time permits.
-Please send any issues or questions to: https://github.com/timtrice/Hurricanes/issues.
- -Use get_storm_data to access one or multiple products for a specific storm.
Not parsed but contains technical information on the cyclone, development tendencies and forecast model tendencies.
-Contains the meat of data. Current storm information, forecast information, wind and sea data. Can use fstadv_split() to break the wide dataframe to multiple, relational dataframes.
Contains current position estimate for a given storm. Usually issued during threats to land. Not issued for all storms. Not parsed.
-Strike probabilities for given locations prior to 2006 (See Wind Speed Probabilities for >= 2006).
-Retrieve list of probability stations based in the Atlantic -basin from the NHC. To be used in tandem with `wndprb` products.
- -al_prblty_stations()
-
- Originally it was believed this data source would be removed by the -National Hurricane Center but it appears to have been updated. Additional -columns have been added, one up front and three in the back. These columns -all contain the same values each and I am unable to find documentation -describing the values.
-Regardless, the data is kept, just in case.
- -Calling al_prblty_stations will generate a warning:
> "Expected 7 pieces. Additional pieces discarded in 1 rows [90]."
-Station PATRICK AFB actually has eight columns. The data is kept for -consistency; you decide if you want it or not.
- - -Build tracking chart centered on Atlantic Basin.
- -al_tracking_chart(...)- -
| ... | -Additional parameters for tracking_chart and ggplot2 |
-
|---|
ggplot2 object centered on Atlantic basin.
- -# NOT RUN { -# Build map with white land areas, thin black borders -al_tracking_chart(color = "black", size = 0.1, fill = "white") - -# 50nm resolution, no states -al_tracking_chart(res = 50, states = FALSE, color = "black", size = 0.1, - fill = "white") - -# 50nm resolution, coastlines only -al_tracking_chart(countries = FALSE, res = 50, color = "black", size = 0.1, - fill = "white") - -# Adding and modifying with ggplot functions -al_tracking_chart(color = "black", size = 0.1, fill = "white") + - ggplot2::labs(x = "Lon", y = "Lat", - title = "Base Atlantic Tracking Chart") -# }-
Retrieve list of probability stations based in the central -Pacific from the NHC. To be used in tandem with `wndprb` products.
- -cp_prblty_stations()
-
-
- R/data.R
- df.al_12_2005_prblty.RdStrike probabilities for Hurricane Katrina (AL122005)
- -df.al_12_2005_prblty
-
- An object of class tbl_df (inherits from tbl, data.frame) with 937 rows and 10 columns.
R/data.R
- df.al_18_2012.RdForecast/Advisory and Wind Speed Probabilities for Hurricane Sandy (AL182012)
- -df.al_18_2012
-
- An object of class list of length 2.
R/data.R
- df.al_18_2012_wndprb.RdWind speed probabilities for Hurricane Sandy (AL182012)
- -df.al_18_2012_wndprb
-
- An object of class tbl_df (inherits from tbl, data.frame) with 2227 rows and 18 columns.
GIS advisory dataset for Hurricane Sandy Adv 18
- -df.gis_adv
-
- An object of class list of length 4.
http://www.nhc.noaa.gov/gis/archive_forecast_results.php?id=al18&year=2012&name=Hurricane%20SANDY
- - -R/data.R
- df.gis_storm_surge.RdGIS storm surge shapefile dataset for Hurricane Sandy (AL182012)
- -df.gis_storm_surge
-
- An object of class list of length 1.
http://www.nhc.noaa.gov/gis/archive_psurge_results.php?id=al18&year=2012&name=Hurricane%20SANDY
- - -R/data.R
- df.gis_wind_radii.RdGIS windfield and forecast wind radii for Hurricane Sandy (AL182012)
- -df.gis_wind_radii
-
- An object of class list of length 2.
Retrieve list of probability stations based in the eastern -Pacific from the NHC. To be used in tandem with `wndprb` products.
- -ep_prblty_stations()
-
- Originally it was believed this data source would be removed by the -National Hurricane Center but it appears to have been updated. Additional -columns have been added, one up front and three in the back. These columns -all contain the same values each and I am unable to find documentation -describing the values.
-Regardless, the data is kept, just in case.
- -Calling ep_prblty_stations will generate a warning:
> "Expected 7 pieces. Missing pieces filled with `NA` in 1 rows [41]."
-Station SALINA CRUZ actually has six columns.
- - -Build tracking chart centered on northeast Pacific Basin.
- -ep_tracking_chart(...)- -
| ... | -Additional parameters for ggplot2 |
-
|---|
ggplot2 object centered on northeast Pacific basin.
- -# NOT RUN { -# Build map with white land areas, thin black borders -ep_tracking_chart(color = "black", size = 0.1, fill = "white") - -# 50nm resolution, no states -ep_tracking_chart(res = 50, states = FALSE, color = "black", size = 0.1, - fill = "white") - -# 50nm resolution, coastlines only -ep_tracking_chart(countries = FALSE, res = 50, color = "black", size = 0.1, - fill = "white") - -# Adding and modifying with ggplot functions -ep_tracking_chart(color = "black", size = 0.1, fill = "white") + - ggplot2::labs(x = "Lon", y = "Lat", - title = "Base East Pacific Tracking Chart") -# }-
For Katrina, 2005, there are two identical discussions; one of - which has 'orig' in the URL. Because this link is not captured above it - will throw an error. This function is an effort to capture it and pass - it through the validation but, at least for this Katrina it is not - necessary. That being said, if there is output for any other storms it - should be reviewed as it is common for the NHC to issue UPDATED statements.
- -filter_orig(links)- -
| links | -Vector of URLs retrieved from storm's archive page. |
-
|---|
Retrieve forecast data from FORECAST/ADVISORY products. Loads - into respective dataframes (df_forecasts, df_forecast_winds)
- -fstadv_forecasts(content, key, adv, adv_date)- -
| content | -text content of FORECAST/ADVISORY |
-
|---|---|
| key | -Storm ID |
-
| adv | -Advisory Number |
-
| adv_date | -Date value of forecast/advisory product. |
-
boolean
- - -Get forward movement direction and speed
- -fstadv_fwd_mvmt(contents, what = NULL)- -
| contents | -text contents of FORECAST/ADVISORY |
-
|---|---|
| what | -is being retrieved
|
-
numeric
- -If STATIONARY should return NA
- - -Returns numeric for latitude or longitude; negative if in - southern or eastern hemisphere
- -fstadv_lat_lon(contents)- -
| contents | -text contents of FORECAST/ADVISORY |
-
|---|
numeric
- -Helper function to take character latitude or longitude and, -depending on the value of hemisphere return a positive or negative numeric, -or NA if not found.
- - -Get storm's previous position
- -fstadv_prev_pos(contents, adv_date)- - -
Parse wind radius data from product, if exists. This is somewhat -tricky as the wind fields are 64KT, 50KT and 34KT and are listed in -descending order. So the first line will not always be 64KT, 50KT or even -34KT depending on strength of storm. What I do here is just extract the -entire blob and work through it. I'll continue to look for ways to improve -it.
-Complimentary to fstadv_get_wind_radius
- -fstadv_wind_radius(content)- -
| contents | -text of product |
-
|---|
dataframe
- - -Return dataframe of discussion data.
Classification of storm, e.g., Tropical Storm, Hurricane, - etc.
Name of storm
Advisory Number
Date of advisory issuance
ID of cyclone
Text content of product
get_discus(links)- -
| links | -URL to storm's archive page. |
-
|---|
# NOT RUN { -# Return dataframe of storm discussions for Tropical Storm Alex (AL011998) -get_discus("http://www.nhc.noaa.gov/archive/1998/1998ALEXadv.html") -# }-
Return dataframe of forecast/advisory data.
- -get_fstadv(links)- -
| links | -URL to storms' archive page. |
-
|---|
Returns a wide dataframe of most the data available in a cyclones -forecast/advisory product (watches and warnings are not included at this -time).
-Overall structure of the dataframe is listed below. Note the following -clarifications:
-The value of `n` in `Hr{n}` variables is the forecast period. - Up to 2002, forecast periods are 12, 24, 36, 48 and 72 hours. After - 2002, forecast periods were extended to 96 and 120 hours. Not all - forecast periods will be available for every cyclone advisory (e.g., - if it is dissipating or expected to dissipate.)
Wind radius data is not included 96 and 120 hour forecast periods.
Forecast dates are not truly 12, 24, ..., 120 hours from the - date/time of the advisory. The NHC issues two positions in these - products; one for current and one for three hours prior. It is the - latter position the forecast date/times are based.
Classification of cyclone
Name of cyclone
Advisory number
Date and time of advisory
Unique identifier of cyclone
Latitude of cyclone center
Longitude of cyclone center
Maximum sustained one-minute winds in knots
Maximum sustained one-minute gusts in knots
Minimum central pressure in millibars
Position accuracy of cyclone in nautical miles
Compass angle of forward motion
Forward speed in miles per hour
Size of eye in nautical miles
Radius of >=64kt winds in northeast quadrant
Radius of >=64kt winds in southeast quadrant
Radius of >=64kt winds in southwest quadrant
Radius of >=64kt winds in northwest quadrant
Radius of >=50kt winds in northeast quadrant
Radius of >=50kt winds in southeast quadrant
Radius of >=50kt winds in southwest quadrant
Radius of >=50kt winds in northwest quadrant
Radius of >=34kt winds in northwest quadrant
Radius of >=34kt winds in southeast quadrant
Radius of >=34kt winds in southwest quadrant
Radius of >=34kt winds in northwest quadrant
Forecast valid date
Forecast latitude in `n` hours
Forecast longitude in `n` hours
Forecast maximum wind in `n` hours
Forecast maximum gust in `n` hours
Forecast wind radius in `n` hours
Forecast wind radius in `n` hours
Forecast wind radius in `n` hours
Forecast wind radius in `n` hours
Forecast wind radius in `n` hours
Forecast wind radius in `n` hours
Forecast wind radius in `n` hours
Forecast wind radius in `n` hours
Forecast wind radius in `n` hours
Forecast wind radius in `n` hours
Forecast wind radius in `n` hours
Forecast wind radius in `n` hours
Radius of 12ft seas in northeast quadrant
Radius of 12ft seas in southeast quadrant
Radius of 12ft seas in southwest quadrant
Radius of 12ft seas in northwest quadrant
# NOT RUN { -# Return dataframe of forecast/advisories for Tropical Storm Alex (AL011998) -get_fstadv("http://www.nhc.noaa.gov/archive/1998/1998ALEXadv.html") -# }-
Get a list of the FTP directors in /atcf/archive
- -get_ftp_dirs(x)- - -
Retrieve text products from the National Hurricane Center's FTP - server. Not all products may exist for certain storms.
- -get_ftp_storm_data(stormid, products = c("discus", "fstadv", "posest", - "public", "prblty", "update", "wndprb"))- -
| stormid | -A six-character alphanumeric string formatted as AABBCCCC -where
|
-
|---|---|
| products | -Products to retrieve; discus, fstadv, posest, public, -prblty, update, and windprb. |
-
Return dataframe of position estimate data.
- -get_posest(links)- -
| links | -URL to storm's archive page. |
-
|---|
This product was discontinued after the 2013 hurricane season and is
-now included in the Tropical Cyclone Update product (update).
Classification of storm, e.g., Tropical Storm, Hurricane, - etc.
Name of storm
Date of advisory issuance
Text content of product
Strike probabilities; the chances of the center of a cyclone -passing within 65 nautical miles of a location.
Classification of storm, e.g., Tropical Storm, Hurricane, - etc.
Name of storm
Advisory Number
Date of advisory issuance
Location for which the probability statistics rely
Probability of a strike within the next 12 hours
Probability of a strike between 12 and 24 hours
Probability of a strike between 24 and 36 hours
Probability of a strike between 36 and 48 hours
Probability of a strike between 48 and 72 hours
get_prblty(links)- -
| links | -URL to storm's archive page. |
-
|---|
This funtion acts as a hub for the individual product extraction - functions. Given the product and links, it will begin the scraping - process and return a dataset for that product.
- -get_product(links, product)- - -
Return dataframe of public advisory data.
Classification of storm, e.g., Tropical Storm, Hurricane, - etc.
Name of storm
Advisory Number
Date of advisory issuance
Unique ID of the cyclone
Text content of product
get_public(links)- -
| links | -URL to storm's archive page. |
-
|---|
Retrieve data from products.
- -get_storm_data(links, products = c("discus", "fstadv", "posest", - "public", "prblty", "update", "wndprb"))- -
| links | -to storm's archive page. |
-
|---|---|
| products | -Products to retrieve; discus, fstadv, posest, public, -prblty, update, and windprb. |
-
list of dataframes for each of the products.
- -get_storm_data is a wrapper function to make it more
- convenient to access the various storm products.
Types of products:
Storm Discussions. This is technical information on the - cyclone such as satellite presentation, forecast model evaluation, etc.
Forecast/Advisory. These products contain the meat of an - advisory package. Current storm information is available as well as - structural design and forecast data.
Position Estimate. Issued generally when a storm is - threatening; provides a brief update on location and winds.
Public Advisory. Issued for public knowledge; more often for - Atlantic than East Pacific storms. Contains general information.
Strike Probability. Discontinued after the 2005 hurricane - season, strike probabilities list the chances of x-force winds in a - particular city.
Cyclone Update. Generally issued when a significant change - occurs in the cyclone.
Wind Probability. Replace strike probabilities beginning in - the 2006 season. Nearly identical.
Progress bars are displayed by default. These can be turned off by setting -the dplyr.show_progress to FALSE. Additionally, you can display messages for -each advisory being worked by setting the rrricanes.working_msg to TRUE.
- -# NOT RUN { -## Get public advisories for first storm of 2016 Atlantic season. -get_storms(year = 2016, basin = "AL") %>% - slice(1) %>% - .$Link %>% - get_storm_data(products = "public") -## Get public advisories and storm discussions for first storm of 2017 Atlantic season. -get_storms(year = 2017, basin = "AL") %>% - slice(1) %>% - .$Link %>% - get_storm_data(products = c("discus", "public")) -# }-
Get storm list
- -get_storm_list()
-
-
- Returns storms and product link.
- -get_storms(years = format(Sys.Date(), "%Y"), basins = c("AL", "EP"))- -
| years | -numeric or vector, four digits (%Y format) |
-
|---|---|
| basins | -One or both of c("AL", "EP") |
-
A 4xN dataframe
Numeric, four-digit year of the storm
Character, name of storm mixed-case
AL (Atlantic) or EP (East Pacific)
URL to storms' product pages
To disable the progress bar set option dplyr.show_progress to FALSE.
- -http://www.nhc.noaa.gov/archive/2016/
- -Dataframe of storms.
- -By default returns all storms for the current year. If no storms -have developed will return an empty dataframe.
- - --# Default. Get all storms, both basins, for last year. -# NOT RUN { -storms <- get_storms(year = 2016, basin = c("AL", "EP")) - -# Get storms for two different years -storms.2010 <- get_storms(c(2010, 2015)) - -# Get storms for two consecutive years, Atlantic basin only -storms.al.2005 <- get_storms(2005:2007, basin = "AL") -# }
Return dataframe of cyclone update data.
Classification of storm, e.g., Tropical Storm, Hurricane, - etc.
Name of storm
Date of advisory issuance
Unique ID of cyclone
Text content of product
get_update(links)- -
| links | -URL to storm's archive page. |
-
|---|
Get contents from URL
- -get_url_contents(links)- -
| link | -URL to download |
-
|---|
This function primarily is reserved for extracting the contents of -the individual products \(thought it can be used in other instances\). Often, -there are timeout issues. This is an attempt to try to work around that.
- - -Return dataframe of wind speed probability data.
- -get_wndprb(links)- -
| links | -URL to storm's archive page. |
-
|---|
http://www.nhc.noaa.gov/about/pdf/About_Windspeed_Probabilities.pdf
- -Wind Speed Probability product replaced Strike Probabilities product - after the 2005 hurricane season. These products may not be issued for - every advisory/cyclone.
-Classification of storm, e.g., Tropical Storm, Hurricane, - etc.
Name of storm
Advisory Number
Date of advisory issuance
Minimum wind speed for which probabilities reference
Probability of sustained `Wind` within 12 hours
Probability of sustained `Wind` within 24 hours
Cumulative probability through 24 hours
Probability of sustained `Wind` within 36 hours
Cumulative probability through 36 hours
Probability of sustained `Wind` within 48 hours
Cumulative probability through 48 hours
Probability of sustained `Wind` within 72 hours
Cumulative probability through 72 hours
Probability of sustained `Wind` within 96 hours
Cumulative probability through 96 hours
Probability of sustained `Wind` within 120 hours
Cumulative probability through 120 hours
Advisory Forecast Track, Cone of Uncertainty, and - Watches/Warnings
- -gis_advisory(key, advisory = as.character())- -
| key | -Key of storm (i.e., AL012008, EP092015) |
-
|---|---|
| advisory | -Advisory number. If NULL, all advisories are returned. -Intermediate advisories are acceptable. |
-
Return link to breakpoints shapefile by year
- -gis_breakpoints()
-
- Coastal areas placed under tropical storm and hurricane watches and - warnings are identified through the use of "breakpoints." A tropical - cyclone breakpoint is defined as an agreed upon coastal location that can - be chosen as one of two specific end points or designated places between - which a tropical storm/hurricane watch/warning is in effect. The U.S. - National Weather Service designates the locations along the U.S. East, - Gulf, and California coasts, Puerto Rico, and Hawaii. These points are - listed in NWS Directive 10-605 (PDF). Individual countries across the - Caribbean, Central America, and South America provide coastal locations - for their areas of responsibility to the U.S. National Weather Service for - the National Hurricane Center's use in tropical cyclone advisories when - watches/warnings are issued by international partners. The National - Hurricane Center maintains a list of pre-arranged breakpoints for the U.S. - Atlantic and Gulf coasts, Mexico, Cuba and the Bahamas. Other sites are - unofficial and sites not on the list can be selected if conditions warrant.
- - -Probabilistic Storm Surge
- -gis_prob_storm_surge(key, products, datetime = NULL)- -
| key | -Key of storm (i.e., AL012008, EP092015) |
-
|---|---|
| products | -list of products and associated n values; psurge (0:20) or -esurge (10, 20, 30, 40, 50). |
-
| datetime | -Datetime in %Y%m%d%H format. |
-
Probabilistic Storm Surge Forecasts
- -The Tropical Cyclone Storm Surge Exceedances (P-Surge 2.5) - data shows the probability, in percent, of a specified storm surge, - including tides, exceeding the specified height, in feet, during the - forecast period indicated. The 10 percent exceedance height, for example, - is the storm surge height, including tides, above ground level (AGL) such - that there is a 10 percent chance of exceeding it. The product is based - upon an ensemble of Sea, Lake,and Overland Surge from Hurricanes (SLOSH) - model runs using the National Hurricane Center (NHC) official advisory - and accounts for track, size, and intensity errors based on historical - errors and astronomical tide. Valid values are 10, 20, 30, 40 or 50.
The Tropical Cyclone Storm Surge Probabilities (P-Surge 2.5) - data shows the probability, in percent, of a specified storm surge - occurring during the forecast period indicated. The product is based upon - an ensemble of Sea, Lake, and Overland Surge from Hurricanes (SLOSH) - model runs using the National Hurricane Center(NHC) official advisory - and accounts for track, size, and intensity errors based on historical - errors and astronomical tide. Valid values are 0:20.
# NOT RUN { -# Return the last psurge0 product for storm AL092016 -gis_prob_storm_surge("AL092016", products = list("psurge" = 0)) - -# Return the psurge0 and esurge10 products for storm AL092016 -gis_prob_storm_surge("AL092016", products = list("psurge" = 0, "esurge" = 10)) - -# Return all psurge0 products for Sep 2, 2016, storm AL092016 -gis_prob_storm_surge("AL092016", products = list("psurge" = 0), - datetime = "20160902") -# }-
Potential Storm Surge Flooding (Inundation)
- -gis_storm_surge_flood(key, advisory = as.numeric(), - products = c("inundation", "tidalmask"))- -
| key | -Key of storm (i.e., AL012008, EP092015) |
-
|---|---|
| advisory | -Advisory number. |
-
| products | -indundation or tidalmask |
-
Advisory Wind Field and Forecast Wind Radii
- -gis_windfield(key, advisory = as.character())- -
| key | -Key of storm (i.e., AL012008, EP092015) |
-
|---|---|
| advisory | -Advisory number. If NULL, all advisories are returned. -Intermediate advisories are acceptable. |
-
Tropical Cyclone Advisory Wind Field - http://www.nhc.noaa.gov/gis/archive_forecast_info_results.php?id=al14&year=2016 - http://www.nhc.noaa.gov/gis/forecast/archive/ -Example file name: al012017_fcst_001.zip -[basin]2[year_num]2[year]4_fcst_[advisory]3.zip -Many storms do not appear to have this data; especially earlier.
-Not all advisories will be available for storms. For example, -Hurricane Matthew (AL142016) -is missing several advisories.
- -Wind Speed Probabilities
- -gis_wsp(datetime, res = c(5, 0.5, 0.1))- -
| datetime | -Datetime in %Y%m%d%H format. %m, %d and %H are -optional but will return more datasets. |
-
|---|---|
| res | -Resolution as a numeric vector; 5, 0.5, 0.1. |
-
Probability winds affecting an area within a forecast period. -Datasets contain windfields for 34kt, 50kt and 64kt. Resolution is at 5km, -0.5 degrees and 0.1 degrees. Not all resolutions may be available for all -storms. Not all windfields will be available for all advisories.
- -# NOT RUN { -# Return datasets for January 1, 2016 with resolution of 0.5 degrees -gis_wsp("20160101", res = 0.5) - -# Return wsp of 0.1 and 0.5 degree resolution, July, 2015 -gis_wsp("201507", res = c(0.5, 0.1)) -# }-
Parse probability station listings for each basin.
- -parse_stations(x)- -
| x | -URL of station list |
-
|---|
At the moment, documentation on the format is unavailable. The -format changed during the 2017/2018 offseason and now includes a -numeric first column and numeric fifth, sixth and seventh column. All -values are identical per column.
-Additionally, as of publication, PATRICK AFB in the Atlantic data source
-actually contains eight columns; this is noted in
-al_prblty_stations. SALINA CRUZ in
-ep_prblty_stations is short one column.
I see no issues with the extra or missing data as I am unsure the value of -the data to begin with. A warning will be given so the user is aware, -but the important pieces (Location, Lat, Lon) all seem good.
- - -Extrapolate data from Position Estimate products.
- -posest(contents)- -
| contents | -URL of a specific position estimate product |
-
|---|
Dataframe
- -Given a direct link to a position estimate product, parse and return -dataframe of values.
- -Parse strike probability products
- -prblty(contents)- -
| contents | -Link to a storm's specific strike probability advisory product. |
-
|---|
Dataframe
- -Given a direct link to a strike probability advisory product, parse -and return dataframe of values.
- -Parse Public Advisory products
- -public(contents)- -
| contents | -Link to a storm's specific public advisory product. |
-
|---|
Dataframe
- -Given a direct link to a public advisory product, parse and return -dataframe of values.
- -rrricanes is a web-scraping library for R designed to deliver -hurricane data (past and current) into well-organized datasets. With these -datasets you can explore past hurricane tracks, forecasts and structure -elements.
-This documentation and additional help articles -can be found online.
-Text products (Forecast/Advisory, Public Advisory, Discussions and -Probabilities) are only available from 1998 to current. An effort will be -made to add prior data as available.
- -List all storms that have developed by year and basin. Year must be in a -four-digit format (%Y) and no earlier than 1998. Basin can be one or both -of Atlantic ("AL") or East Pacific ("EP").
get_stormsList all storms by year, basin
get_storm_data can be used to select multiple products,
-multiple storms and from multiple basins.
Additional text products are:
get_discusStorm Discussions
get_fstadvForecast/Advisory. These products contain a - bulk of the information for tropical cyclones including current position, - structure, forecast position and forecast structure.
get_posestPosition Estimates. Rare and used generally
- for threatening cyclones. This product was discontinued after the 2013
- season and is now issued as get_update.
get_prbltyStrike Probabilities. Show the probability
- of the center of a cyclone passing within 65nm of a location for a given
- forecast period. This product was discontinued after 2005, replaced with
- get_wndprb.
get_publicPublic Advisory. General non-structured - information exists in these products.
get_updateUpdates. Generally issued when a cyclone - undergoes a sudden change that requires immediate notice.
get_wndprbWind Speed Probability. Lists the
- probability of a location experiencing a minimum of 35kt, 50kt or 64kt
- winds for an alotted forecast period or accumulated probability. This
- product replaced get_prblty after the 2005 season.
The products above may take some time to load if the NHC website is slow (as
-is often the case, unfortunately). For all storm advisories issued outside
-of the current month, use the rrricanesdata package.
To install rrricanesdata, run
See vignette("installing_rrricanesdata", package = "rrricanes") for
-more information.
For enhanced plotting of storm data, several GIS datasets are available. The -core GIS functions return URLs to help you refine the data you wish to view. -(Some products will not exist for all storms/advisories). These products are:
-gis_advisoryPast track, current position, forecast - and wind radii
gis_breakpointsBreakpoints for watches and warnings
gis_latestAll available GIS products for active - cyclones
gis_outlookTropical Weather Outlook
gis_prob_storm_surgeProbabilistic Storm Surge
gis_windfieldWind Radii
gis_wspWind Speed Probabilities
gis_download will download the datasets from the above
-functions.
Some GIS datasets will need to be converted to dataframes to plot geoms. Use
-shp_to_df to convert SpatialLinesDataFrames and
-SpatialPolygonsDataFrames. SpatialPointsDataFrames can be converted using
-tibble::as_data_frame targeting the @data object.
dplyr.show_progress displays the dplyr progress bar when scraping raw
-product datasets. In get_storms, it is based on the number of
-years being requested. In the product functions (i.e.,
-get_fstadv) it is based on the number of advisories. It can be
-misleading when calling get_storm_data because it shows the
-progress of working through a storm's product advisories but will reset on
-new products/storms.
dplyr.show_progress displays the dplyr progress bar when scraping raw
-product datasets. In get_storms, it is based on the number of
-years being requested. In the product functions (i.e.,
-get_fstadv) it is based on the number of advisories. It can be
-misleading when calling get_storm_data because it shows the
-progress of working through a storm's product advisories but will reset on
-new products/storms.
rrricanes.working_msg is set to FALSE by default. When TRUE, it will
-list the current storm, advisory and date being worked.
Extract status, name, and advisory from products header.
- -scrape_header(contents, ptn_product_title, advisory_number = TRUE)- -
| contents | -Text product |
-
|---|---|
| ptn_product_title | -Pattern of product title to match |
-
| advisory_number | -Default is true; set to false if product does not -have an advisory number. |
-
Convert Status abbreviation to string
- -status_abbr_to_str(x)- -
| x | -character vector of status abbreviations |
-
|---|
character vector of strings
- -Status abbreviations
Disturbance (of any intensity)
Extratropical cyclone (of any intensity)
Tropical cyclone of hurricane intensity (> 64 knots)
A low that is neither a tropical cyclone, a subtropical - cyclone, nor an extratropical cyclone (of any intensity)
Subtropical cyclone of subtropical depression intensity - (< 34 knots)
Subtropical cyclone of subtropical storm intensity - (> 34 knots)
Tropical cyclone of tropical depression intensity (< 34 knots)
Tropical cyclone of tropical storm intensity (34-63 knots)
Tropical Wave (of any intensity)
-# Extratropical Cyclone -status_abbr_to_str("EX")#> [1] "Extratropical Cyclone"-# Hurricane -status_abbr_to_str("HU")#> [1] "Hurricane"
Tidy current details of a fstadv dataframe object.
-tidy_fstadv will be deprecated in 0.2.2
tidy_adv(df) - -tidy_fstadv(df)- -
| df | -fstadv dataframe object |
-
|---|
Returns current data only of a fstadv dataframe. Use Key, Adv and -Date to join with other tidy dataframes.
Unique identifier of cyclone
Advisory number
Date and time of advisory
Classification of cyclone
Name of cyclone
Latitude of cyclone center
Longitude of cyclone center
Maximum sustained one-minute winds in knots
Maximum sustained one-minute gusts in knots
Minimum central pressure in millibars
Position accuracy of cyclone in nautical miles
Compass angle of forward motion
Forward speed in miles per hour
Size of eye in nautical miles
Radius of 12ft seas in northeast quadrant
Radius of 12ft seas in southeast quadrant
Radius of 12ft seas in southwest quadrant
Radius of 12ft seas in northwest quadrant
# NOT RUN { -get_fstadv("http://www.nhc.noaa.gov/archive/1998/1998ALEXadv.html") %>% - tidy_adv() -# }-
Tidy forecasts of a fstadv dataframe object.
- -tidy_fcst(df)- -
| df | -fstadv dataframe object |
-
|---|
Gathers all forecast points, tidies dataframe to make one row per -forecast position. Complete cases only. Use Key, Adv and Date to join with -other tidy dataframes.
-Unique identifier of cyclone
Advisory number
Date and time of advisory
Forecast date and time in UTC
Forecast latitude
Forecast Longitude
Forecast wind in knots
Forecast gust in knots
# NOT RUN { -get_fstadv("http://www.nhc.noaa.gov/archive/1998/1998ALEXadv.html") %>% - tidy_fcst() -# }-
Tidy forecast wind radii of a fstadv dataframe object
- -tidy_fcst_wr(df)- -
| df | -fstadv dataframe object |
-
|---|
Tidies forecast wind radius for each forecast position. Complete -cases only (by quadrants). Use Key, Adv and Date to join with other tidy -dataframes.
-Unique identifier of cyclone
Advisory number
Date and time of advisory
Forecast date and time in UTC
Minimum sustained wind field for quadrants
Radius in nautical miles for northeast quadrant
Radius in nautical miles for southeast quadrant
Radius in nautical miles for southwest quadrant
Radius in nautical miles for northwest quadrant
# NOT RUN { -get_fstadv("http://www.nhc.noaa.gov/archive/1998/1998ALEXadv.html") %>% - tidy_fcst_wr() -# }-
Tidy current wind radius of a fstadv dataframe object.
- -tidy_wr(df)- -
| df | -fstadv dataframe object |
-
|---|
Returns tidy dataframe of current wind radius values for a cyclone. -Returns only complete.cases (based on quadrants).
Unique identifier of cyclone
Advisory number
Date and time of advisory
Minimum wind speed expected
Radius of `Windfield` in the northeast quadrant
Radius of `Windfield` in the southeast quadrant
Radius of `Windfield` in the southwest quadrant
Radius of `Windfield` in the northwest quadrant
# NOT RUN { -get_fstadv("http://www.nhc.noaa.gov/archive/1998/1998ALEXadv.html") %>% - tidy_wr() -# }-
Build base tracking chart using ggplot
- -tracking_chart(countries = TRUE, states = TRUE, res = 110, ...)- -
| countries | -Show country borders. Default TRUE. |
-
|---|---|
| states | -Show state boundaries. Default TRUE. Ignored if `countries` is -FALSE. |
-
| res | -Resolution of charts; 110 (1:110m), 50 (1:50m), 10 (1:10m). -Default is low. The higher the resolution, the longer the plot takes to -appear. |
-
| ... | -Additional ggplot2::aes parameters |
-
Returns ggplot2 object that can be printed directly or have new - layers added.
- -# NOT RUN { -# Build map with white land areas, thin black borders -tracking_chart(color = "black", size = 0.1, fill = "white") - -# 50nm resolution, no states -tracking_chart(res = 50, states = FALSE, color = "black", size = 0.1, - fill = "white") - -# 50nm resolution, coastlines only -tracking_chart(countries = FALSE, res = 50, color = "black", size = 0.1, - fill = "white") - -# Adding and modifying with ggplot functions -tracking_chart(color = "black", size = 0.1, fill = "white") + - ggplot2::labs(x = "Lon", y = "Lat", title = "Base Tracking Chart") -# }-
Atlantic Tropical Weather Outlook
- -twoal()
-
- This function parses the latest xml tropical weather outlook for -the Atlantic ocean. The core data is located in the `channel$item` element -where `title`, `description` and `pubDate` reside. `link` is also -available to point to the NHC website.
- - -East Pacific Tropical Weather Outlook
- -twoep()
-
- This function parses the latest xml tropical weather outlook for -the east Pacific. The core data is located in the `channel$item` element -where `title`, `description` and `pubDate` reside. `link` is also -available to point to the NHC website.
- - -Parse cyclone update products
- -update(contents)- -
| contents | -Link to a storm's specific update advisory product. |
-
|---|
Dataframe
- -Given a direct link to a cyclone update product, parse and return -dataframe of values.
- -library(HURDAT)
-library(knitr)
-library(purrr)
-library(rrricanes)
-## rrricanes is not intended for use in emergency situations.
-library(rrricanesdata)
-library(stringr)
-gis <- flatten(gis_latest(verbose = FALSE))
-# Keys of existing storms
-keys <- str_extract(names(gis), "(^[[:alpha:]]{2}[[:digit:]]{6})") %>%
- toupper() %>%
- unique() %>%
- .[complete.cases(.)]
-keys_al <- keys[str_which(keys, "^AL.")]
-if (is_empty(keys_al)) {
- src <- "There are no storms in the Atlantic basin."
-} else {
- src <- walk(keys_al, function(x) {
- knit_expand(file = "child_storm.Rmd",
- arguments = list(key = x))
- })
-}
-AL112017
-(keys_ep <- keys[str_which(keys, "^EP.")])
-## [1] "EP142017"
-