HURDAT v0.2.0

library(ggridges)
library(HURDAT)
library(lubridate)
library(tidyverse)
df <- union(AL, EP) %>% 
  mutate(Basin = case_when(
    str_sub(Key, 0L, 2L) == "AL" ~ "Atlantic", 
    str_sub(Key, 0L, 2L) == "EP" ~ "East Pacific", 
    str_sub(Key, 0L, 2L) == "CP" ~ "Central Pacific"))
df %>% 
  group_by(Basin, 
           Year = year(DateTime)) %>% 
  summarise(Storms = n_distinct(Key)) %>% 
  mutate(Decade = paste0(10 * floor(Year/10), "'s")) %>% 
  ggplot(aes(x = Year, y = Storms, fill = Decade, color = Decade)) + 
  geom_ribbon(aes(ymin = 0, ymax = Storms), alpha = 0.35, color = NA) + 
  geom_line(size = 0.5) + 
  facet_wrap(~Basin, ncol = 1) + 
  scale_x_continuous(limits = c(1851, 2018), 
                     breaks = seq(1850, 2020, by = 20), 
                     minor_breaks = seq(1850, 2020, by = 10), 
                     expand = c(0, 0)) + 
  scale_y_continuous(limits = c(0, 35), 
                     expand = c(0, 0)) + 
  theme_bw() + 
  theme(legend.position = "none", 
        plot.subtitle = element_text(face = "italic", size = 10),
        strip.text = element_text(size = 10, color = "black", face = "bold", 
                                  hjust = 0.99), 
        strip.background = element_rect(fill = "#FFFFFF")) + 
  labs(title = "Tropical cyclones by decade", 
       subtitle = "Introduction of weather satellites in 1960's", 
       caption = sprintf("@timtrice, HURDAT %s", packageVersion("HURDAT")))

df %>% 
  mutate(Month = factor(month(DateTime, label = TRUE))) %>% 
  ggplot(aes(x = Wind, y = Month)) + 
  geom_density_ridges_gradient(aes(fill = ..x..), 
                               alpha = 0.85, 
                               scale = 0.85, 
                               rel_min_height = 0.01, 
                               size = 0.1) + 
  facet_wrap(~Basin, ncol = 1) + 
  coord_flip() +
  scale_y_discrete(expand = c(0, 0)) + 
  scale_fill_gradientn(colors = terrain.colors(10), name = "Wind Speed (kts)") + 
  theme_bw() + 
  theme(legend.position = "bottom", 
        plot.subtitle = element_text(face = "italic", size = 10),
        axis.text.x = element_text(hjust = -0.75), 
        axis.ticks.x = element_blank(), 
        strip.text = element_text(size = 10, color = "black", face = "bold", 
                                  hjust = 0.99), 
        strip.background = element_rect(fill = "#FFFFFF")) + 
  labs(title = "Wind Observations by Month", 
       subtitle = "No known cyclones for Central Pacific from April through June.", 
       caption = sprintf("@timtrice, HURDAT %s", packageVersion("HURDAT")), 
       x = "Wind (kts)", 
       y = "")
## Warning in seq.default(.limits[1], .limits[2], length = guide$nbin):
## partial argument match of 'length' to 'length.out'

Average Speed of Tropical Cyclones over Time

# @source: http://www.ridgesolutions.ie/index.php/2013/11/14/algorithm-to-calculate-speed-from-two-gps-latitude-and-longitude-points-and-time-difference/
distance <- function(lat1, lon1, lat2, lon2) {

    # Convert degrees to radians
    lat1 = lat1 * pi / 180.0
    lon1 = lon1 * pi / 180.0
 
    lat2 = lat2 * pi / 180.0
    lon2 = lon2 * pi / 180.0
 
    # radius of earth in metres
    r = 6378100;
 
    # P
    rho1 = r * cos(lat1)
    z1 = r * sin(lat1)
    x1 = rho1 * cos(lon1)
    y1 = rho1 * sin(lon1)
 
    # Q
    rho2 = r * cos(lat2)
    z2 = r * sin(lat2)
    x2 = rho2 * cos(lon2)
    y2 = rho2 * sin(lon2)
 
    # Dot product
    dot = (x1 * x2 + y1 * y2 + z1 * z2)
    cos_theta = dot / (r * r)
 
    theta = acos(cos_theta)
 
    # Distance in Metres
    return(r * theta)
}

# meters to miles
m_to_miles <- function(x) {
  return(x * 3.281 / 5280)
}
tmp <- df %>% 
  arrange(Key, DateTime) %>% 
  group_by(Key) %>% 
  summarise(Span = (last(DateTime) - first(DateTime))) %>% 
  filter(Span >= 1) %>% 
  left_join(df, by = "Key") %>% 
  group_by(Key, Year = year(DateTime)) %>% 
  mutate(Distance = distance(Lat, Lon, lag(Lat), lag(Lon)), 
         TimeDiff = as.integer(abs(DateTime - lag(DateTime))), 
         MPH = m_to_miles(Distance/TimeDiff)) %>% 
  summarise(AvgSpeed = mean(MPH, na.rm = TRUE)) %>% 
  mutate(Basin = case_when(
    str_sub(Key, 0L, 2L) == "AL" ~ "Atlantic", 
    str_sub(Key, 0L, 2L) == "CP" ~ "Central Pacific", 
    str_sub(Key, 0L, 2L) == "EP" ~ "East Pacific"
  ))
## Warning in acos(cos_theta): NaNs produced

## Warning in acos(cos_theta): NaNs produced

## Warning in acos(cos_theta): NaNs produced

## Warning in acos(cos_theta): NaNs produced

## Warning in acos(cos_theta): NaNs produced

## Warning in acos(cos_theta): NaNs produced

## Warning in acos(cos_theta): NaNs produced

## Warning in acos(cos_theta): NaNs produced

## Warning in acos(cos_theta): NaNs produced

## Warning in acos(cos_theta): NaNs produced

## Warning in acos(cos_theta): NaNs produced

## Warning in acos(cos_theta): NaNs produced

## Warning in acos(cos_theta): NaNs produced

## Warning in acos(cos_theta): NaNs produced

## Warning in acos(cos_theta): NaNs produced

## Warning in acos(cos_theta): NaNs produced

## Warning in acos(cos_theta): NaNs produced

## Warning in acos(cos_theta): NaNs produced

## Warning in acos(cos_theta): NaNs produced
tmp %>% 
  ggplot(aes(x = Year, y = AvgSpeed)) + 
  geom_point() + 
  geom_smooth(method = "loess") +
  theme_bw() + 
  labs(title = "Average Forward Speed of Storms", 
       subtitle = "Storms with at least 24 hours of data", 
       caption = sprintf("@timtrice, HURDAT %s", packageVersion("HURDAT")), 
       y = "Average Speed (MPH)")

tmp %>% 
  group_by(Basin, Year) %>% 
  summarise(AvgSpeed = mean(AvgSpeed, na.rm = TRUE)) %>% 
  ggplot(aes(x = Year, y = AvgSpeed)) + 
  geom_point() + 
  geom_smooth(method = "loess") + 
  facet_wrap(~Basin, ncol = 1) + 
  scale_x_continuous(breaks = seq(1850, 2020, by = 20), 
                     minor_breaks = seq(1850, 2020, by = 10)) + 
  theme_bw() + 
  theme(strip.text = element_text(size = 10, color = "black", face = "bold", 
                                  hjust = 0.99), 
        strip.background = element_rect(fill = "#FFFFFF")) + 
  labs(title = "Average Forward Speed for All Storms by Year", 
       subtitle = "Storms with at least 24 hours of data", 
       caption = sprintf("@timtrice, HURDAT %s", packageVersion("HURDAT")), 
       y = "Average Speed (MPH)")

First date of tropical storm or hurricane (or subtropical storm). Hurricane status is included for systems that did not officially go through a tropical storm phase, such as AL011851.

df %>% 
  filter(Status %in% c("TS", "HU")) %>% 
  arrange(DateTime) %>% 
  group_by(Year = year(DateTime)) %>% 
  slice(1L) %>%
  mutate(Month = month(DateTime, label = TRUE)) %>% 
  select(Status, Year, Month) %>% 
  ggplot(aes(x = Month, fill = Status, color = Status)) + 
  geom_bar() + 
  theme_bw() + 
  theme(legend.position = "bottom") + 
  labs(title = "First Tropical Storm or Hurricane Observation, by Month", 
       subtitle = "Extratropical and subtropical cyclones excluded", 
       caption = sprintf("@timtrice, HURDAT %s", packageVersion("HURDAT")), 
       x = "Month", 
       y = "Total")

calendar <- data.frame(Date = seq.Date(as.Date("2016-01-01"),
                                       as.Date("2016-12-31"), by = 1)) %>% 
  mutate(DOY = strftime(Date, format = "%j"), 
         Month = month(Date, label = TRUE)) %>% 
  group_by(Month) %>% 
  slice(c(1L, n())) %>% 
  select(DOY, Month) %>% 
  mutate(Breaks = case_when(
    row_number() %% 2 != 0 ~ "Start", 
    TRUE                   ~ "End"
  )) %>% 
  spread(Breaks, DOY) %>% 
  mutate_at(vars(Start, End), .funs = as.numeric)

df %>% 
  filter(Status %in% c("TS", "HU")) %>% 
  arrange(DateTime) %>% 
  group_by(Year = year(DateTime)) %>% 
  slice(1L) %>% 
  mutate(Month = month(DateTime), 
         DOY = as.numeric(format(DateTime, format = "%j"))) %>% 
  ggplot() + 
  geom_bar(aes(x = DOY)) + 
  geom_rect(data = calendar, 
            mapping = aes(xmin = Start, xmax = End, ymin = -Inf,
                                 ymax = Inf, fill = Month), alpha = 0.25) + 
  scale_x_continuous(expand = c(0, 0), 
                     breaks = seq(1, 366, by = 366/12), 
                     minor_breaks = NULL, 
                     labels = month.abb) + 
  scale_y_continuous(expand = c(0, 0)) + 
  scale_fill_hue(h = c(0, 350), l = 50) + 
  theme_bw() + 
  theme(legend.position = "none", 
        axis.text.x = element_text(hjust = -0.90)) + 
  labs(title = "First Tropical Storm or Hurricane Observation, by Date", 
       subtitle = "Extratropical and subtropical cyclones excluded", 
       caption = sprintf("@timtrice, HURDAT %s", packageVersion("HURDAT")), 
       x = "", 
       y = "Total")

Next
Previous
comments powered by Disqus