This document demonstrates how to use R to determine HIP-WI county level triggers.
If you would like to run this code for a specific storm, search for
Dorian, 2019
within the code and replace it with the
desired storm.
If you are a Windows user, you may need to install Rtools in addition to R in order to run this example.
The following sections break up this demonstration into parts. The complete code without breaks is available at the end of the document.
The following code downloads the necessary R packages to a temporary
directory, and loads for the current R session. If you run into issues
running this section, you can always do a traditional install
install.packages("package_name_here")
and loading
library(package_name_here)
.
If you use this traditional method, remove
Sys.setenv(TMPDIR=tempdir())
and
if (!require("pacman")) install.packages("pacman")
from the
code, and restart your R session.
Sys.setenv(TMPDIR=tempdir())
if (!require("pacman")) install.packages("pacman")
pacman::p_install_version("tidyverse", "1.3.1")
pacman::p_load(tidyverse)
pacman::p_load(lubridate)
pacman::p_install_version("pins", "1.0.1")
pacman::p_load(pins)
pacman::p_install_version("sf", "1.0-7")
pacman::p_load(sf)
pacman::p_install_version("tigris", "1.6.1")
pacman::p_load(tigris)
pacman::p_install_version("geosphere", "1.5-14")
pacman::p_load(geosphere)
pacman::p_install_version("units", "0.8-0")
pacman::p_load(units)
pacman::p_install_version("janitor", "2.1.0")
pacman::p_load(janitor)
pacman::p_install_version("curl", "4.3.2")
pacman::p_load(curl)
pacman::p_install_version("rnaturalearth", "0.1.0")
pacman::p_load(rnaturalearth)
pacman::p_install_version("kableExtra", "1.3.4")
pacman::p_load(kableExtra)
pacman::p_install_version("lutz", "0.3.1")
pacman::p_load(lutz)
theme_set(theme_bw())
The following code prepares shape files for mapping and determining county triggers.
counties_t <- counties(
state = c(
'01',
'05',
'09',
'10',
'12',
'13',
'15',
'22',
'23',
'24',
'25',
'28',
'33',
'34',
'36',
'37',
'42',
'44',
'45',
'48',
'50',
'51'
),
cb = FALSE,
year = 2020,
progress_bar = FALSE,
class = "sf"
) %>%
mutate(
center_point = st_centroid(geometry),
county_timezone = tz_lookup(center_point, method = "accurate")
) %>%
janitor::clean_names() %>%
select(
namelsad,
geoid,
geometry,
county_timezone
) %>%
rename(
county_name = namelsad
)
counties_4326 <- st_transform(counties_t, crs=4326) %>%
st_sf(crs=4326)
remove(counties_t)
## Altering the Monroe County Florida Shapefile
## "Any part of Monroe County, Florida south of Latitude 25˚ North, as identified by the United States Census Bureau, will not be used for the purpose of determining an adjacent county loss trigger under the Hurricane Insurance Protection-Wind Index Endorsement."
counties_4326_12087 <- counties_4326 %>%
filter(
geoid == "12087"
)
bbox_original_12087 <-st_bbox(counties_4326_12087)
bbox_crop_12087 <- bbox_original_12087
bbox_crop_12087[[2]] <- 25
counties_4326_12087_crop <- st_crop(
counties_4326_12087 ,
bbox_crop_12087
) %>%
mutate(
geometry = geometry %>% st_sfc(crs=4326)
) %>%
st_sf(crs=4326)
counties_4326_12087_psudo <- st_difference(
counties_4326_12087 %>% st_make_valid(),
counties_4326_12087_crop %>% st_make_valid()
) %>%
select(
county_name,
geoid,
geometry,
county_timezone
) %>%
mutate(
county_name = "Monroe Keys County",
geoid = "12087.2",
geoid_neighbor = "12087"
)
## Altering the Honolulu County Shapefile
## "The trailing islands in the state of Hawaii, defined by the United States Census Bureau as Census Tract 114.98 of Honolulu County, shall not constitute a triggered county or county adjacent to a triggered county for purposes of determining a county loss trigger under the Hurricane Insurance Protection-Wind Index Endorsement."
counties_4326_15003 <- counties_4326 %>%
filter(
geoid == "15003"
)
bbox_original_15003 <-st_bbox(counties_4326_15003)
bbox_crop_15003 <- bbox_original_15003
bbox_crop_15003[[4]] <- 22
counties_4326_15003_crop <- st_crop(
counties_4326_15003,
bbox_crop_15003
)
## Updating the County File
counties_4326_update <- counties_4326 %>%
mutate(
geometry = ifelse(
geoid == "12087",
counties_4326_12087_crop$geometry,
ifelse(
geoid == "15003",
counties_4326_15003_crop$geometry,
geometry
)
) %>%
st_sfc(crs=4326)
) %>%
st_sf(crs=4326)
## US Census Bureau County Adjacency File
county_adjacency_pin <- pin("https://www2.census.gov/geo/docs/reference/county_adjacency.txt")
county_adjacency <- read_delim(
county_adjacency_pin,
"\t",
escape_double = FALSE,
trim_ws = TRUE,
col_names = FALSE
) %>%
select(
X2,
X4
) %>%
rename(
geoid = X2,
geoid_neighbor = X4
) %>%
fill(geoid, .direction="down") %>%
group_by(geoid) %>%
nest() %>%
ungroup()
counties_4326_update <- left_join(
counties_4326_update %>%
select(
county_name,
geoid,
county_timezone
),
county_adjacency
) %>%
full_join(
counties_4326_12087_psudo %>%
tibble() %>%
nest(data=c("geoid_neighbor"))
) %>%
drop_na(
geometry,
data
)
counties_5070_update <- counties_4326_update %>% st_transform(crs=5070)
The following temporarily downloads International Best Track Archive for Climate Stewardship (IBTrACS) data from NOAA. If you are going to run this program more than once, consider downloading the data locally to speed up processing and reduce burden on NOAA servers.
# IBTrACS
ibtracs_shape_zip <- tempfile()
curl_download(
'https://www.ncei.noaa.gov/data/international-best-track-archive-for-climate-stewardship-ibtracs/v04r00/access/shapefile/IBTrACS.since1980.list.v04r00.points.zip',
ibtracs_shape_zip
)
ibtracs_shape_unzip <- tempfile()
unzip(
zipfile = ibtracs_shape_zip,
exdir = ibtracs_shape_unzip
)
remove(ibtracs_shape_zip)
ibtracs_shape <- list.files(
ibtracs_shape_unzip,
pattern = ".shp$",
full.names = TRUE
)
remove(ibtracs_shape_unzip)
ibtracs_4326 <- read_sf(ibtracs_shape) %>%
clean_names() %>%
select(
usa_atcfid,
usa_wind,
usa_pres,
name,
season,
basin,
iso_time,
starts_with("usa_r64"),
track_type
) %>%
filter(
basin %in% c("NA", "EP")
) %>%
mutate(
name = name %>% str_to_title(),
storm_name = str_c(
name,
usa_atcfid %>% str_trunc(4, side = "left", ellipsis = ""),
sep = ", "
) %>%
str_trim(),
season = season %>% as.numeric(),
iso_time = iso_time %>% as_datetime()
) %>%
select(-name) %>%
mutate(
across(
starts_with("usa_r"),
as.numeric
)
) %>%
filter(
storm_name=="Dorian, 2019"
)
remove(ibtracs_shape)
The following code creates hurricane corridors using the methods described in the HDP.
# Constructing Hurricane Corridors
bearing_map <- function(geometry, lon_lead, lat_lead) {
bearing(
st_coordinates(geometry),
c(lon_lead, lat_lead)
) %>%
set_units(degrees)
}
## Another storm can be selected here
points_4326 <- ibtracs_4326 %>%
arrange(iso_time) %>%
group_by(usa_atcfid) %>%
mutate(
lat = map(geometry, 2) %>% unlist(),
lon = map(geometry, 1) %>% unlist(),
lat_lead = lead(lat),
lon_lead = lead(lon),
lat_lag = lag(lat),
lon_lag = lag(lon),
usa_wind_lead = lead(usa_wind),
usa_wind_lag = lag(usa_wind),
point_prior_hu = if_else(
usa_wind_lead >= 64 & usa_wind < 64,
1,
0
),
point_after_hu = if_else(
usa_wind_lag >= 64 & usa_wind < 64,
1,
0
),
hu = if_else(usa_wind >= 64, 1, 0) %>% as_factor,
# Nautical Miles to Meters
wind_extent_hu_m = pmax(
usa_r64_ne,
usa_r64_se,
usa_r64_nw,
usa_r64_sw,
na.rm = T
)*1852,
bearing_accurate = pmap(
.l = list(
geometry=geometry,
lon_lead=lon_lead,
lat_lead=lat_lead
),
.f = bearing_map
)
) %>%
ungroup() %>%
rowwise() %>%
mutate(
distance_to_next = distGeo(
c(lon, lat),
c(lon_lead, lat_lead)
),
wind_extent_hu_m = wind_extent_hu_m %>% replace_na(0)
) %>%
ungroup()
buffers_5070 <- points_4326 %>%
st_transform(crs=5070) %>%
ungroup() %>%
mutate(
geometry = st_buffer(
st_geometry(.),
dist = wind_extent_hu_m,
nQuadSegs = 180
)
) %>%
ungroup()
## Interpolating Hurricane Status Transition Points
### Hurricane Dissolution (end points)
points_4326_e1 <- points_4326 %>%
arrange(iso_time) %>%
group_by(usa_atcfid) %>%
mutate(
lag_wind_extent_hu_m = lag(wind_extent_hu_m),
lag_distance_to_next = lag(distance_to_next),
bearing_accurate = lag(bearing_accurate),
lag_iso_time = lag(iso_time)
) %>%
ungroup() %>%
filter(point_after_hu==1) %>%
mutate(
mid_distance_to_lead = lag_distance_to_next*((usa_wind_lag - 64)/(usa_wind_lag - usa_wind)),
wind_extent_hu_m_guess_last =
pmax(
lag_wind_extent_hu_m/2,
lag_wind_extent_hu_m*(1 -((usa_wind_lag - 64)/(usa_wind_lag - usa_wind)))
),
iso_time = iso_time - minutes(
round(
difftime(
iso_time,
lag_iso_time,
units = "mins"
)*(mid_distance_to_lead/lag_distance_to_next)
)
),
wind_extent_hu_m = wind_extent_hu_m_guess_last,
interpolated_hu = T,
hu = 1 %>% as_factor,
distance_to_next = mid_distance_to_lead,
usa_wind = 64
) %>%
arrange(iso_time) %>%
select(
usa_atcfid,
storm_name,
season,
iso_time,
wind_extent_hu_m,
bearing_accurate,
lon,
lon_lag,
lat,
lat_lag,
usa_wind,
interpolated_hu,
hu,
distance_to_next,
basin
) %>%
ungroup()
points_4326_e2 <- points_4326_e1
for (i in 1:dim(points_4326_e2)[1]) {
points_4326_e2$geometry[i] <- destPoint(
c(
points_4326_e2$lon_lag[i],
points_4326_e2$lat_lag[i]
),
points_4326_e2$bearing_accurate[i],
points_4326_e2$distance_to_next[i]
) %>% st_point() %>% st_sfc()
}
interpolated_end_hu_5070 <- points_4326_e2 %>%
select(
-lat,
-lat_lag,
-lon,
-lon_lag
) %>%
st_transform(crs=5070) %>%
ungroup() %>%
mutate(
geometry = st_buffer(
st_geometry(.),
dist = wind_extent_hu_m,
nQuadSegs = 180
)
) %>%
ungroup()
### Hurricane Inception (start points)
points_4326_s1 <- points_4326 %>%
arrange(iso_time) %>%
group_by(usa_atcfid) %>%
mutate(
lead_wind_extent_hu_m = lead(wind_extent_hu_m),
lead_iso_time = lead(iso_time)
) %>%
filter(point_prior_hu==1) %>%
ungroup() %>%
mutate(
mid_distance_to_lead = distance_to_next*(1-(usa_wind_lead - 64)/(usa_wind_lead - usa_wind)),
wind_extent_hu_m_guess_first =
pmax(
lead_wind_extent_hu_m/2,
lead_wind_extent_hu_m*(1 -((usa_wind_lead - 64)/(usa_wind_lead - usa_wind)))
),
iso_time = iso_time + minutes(
round(
difftime(
lead_iso_time,
iso_time,
units = "mins"
) *(mid_distance_to_lead/distance_to_next)
)
),
wind_extent_hu_m = wind_extent_hu_m_guess_first,
interpolated_hu = T,
hu = 1 %>% as_factor,
distance_to_next = mid_distance_to_lead,
usa_wind = 64,
) %>%
arrange(iso_time) %>%
select(
usa_atcfid,
storm_name,
season,
iso_time,
wind_extent_hu_m,
bearing_accurate,
lon,
lat,
distance_to_next,
usa_wind,
interpolated_hu,
hu,
basin
)
points_4326_s2 <- points_4326_s1
for (i in 1:dim(points_4326_s2)[1]) {
points_4326_s2$geometry[i] <- destPoint(
c(
points_4326_s2$lon[i],
points_4326_s2$lat[i]
),
points_4326_s2$bearing_accurate[i],
points_4326_s2$distance_to_next[i]
) %>% st_point() %>% st_sfc()
}
interpolated_start_hu_5070 <- points_4326_s2 %>%
select(
-lat,
-lon
) %>%
st_transform(crs=5070) %>%
ungroup() %>%
mutate(
geometry = st_buffer(
st_geometry(.),
dist = wind_extent_hu_m,
nQuadSegs = 180
)
) %>%
ungroup()
remove(points_4326)
### Combine Interpolated Data
buffers_5070_new <- buffers_5070 %>%
as_tibble() %>%
mutate(
interpolated_hu = F
) %>%
full_join(
interpolated_start_hu_5070 %>%
as_tibble()
) %>%
full_join(
interpolated_end_hu_5070 %>%
as_tibble()
) %>%
st_sf(crs=5070)
remove(buffers_5070)
### Creating Polygon Pairs
status_change_function <- function(x) {
x <- rle(x)$lengths
rep(seq_along(x), times=x)
}
poly_5070 <- buffers_5070_new %>%
ungroup() %>%
arrange(usa_atcfid, iso_time) %>%
mutate(
hu_status_change = status_change_function(hu %>% as.numeric())
) %>%
group_by(usa_atcfid, hu, hu_status_change) %>%
mutate(
geometry_lag = lag(geometry) %>% st_sfc()
) %>%
slice(2:n()) %>%
ungroup()
geo_union_function <- function(x, y, ...) st_union(x, y)
poly_5070$geometry <- map2(
poly_5070$geometry,
poly_5070$geometry_lag,
geo_union_function
)
poly_5070 <- poly_5070 %>%
select(-geometry_lag) %>%
mutate(
geometry = st_sfc(geometry, crs = 5070)
)
### Convex Hull
hull_5070 <- poly_5070 %>%
group_by(usa_atcfid, iso_time) %>%
mutate(
geometry = st_convex_hull(geometry)
) %>%
ungroup()
remove(poly_5070)
The following code finds the intersection of the hurricane corridor and the county shape files prepared in previous steps.
# Finding Triggered Counties
triggered_direct <- st_intersection(
hull_5070,
counties_5070_update %>%
st_make_valid()
) %>%
tibble() %>%
select(-geometry) %>%
arrange(usa_atcfid, iso_time) %>%
group_by(usa_atcfid, geoid) %>%
ungroup() %>%
select(
usa_atcfid,
geoid,
county_name,
data,
storm_name,
season,
iso_time,
interpolated_hu
)
triggered_direct_4326_t <- triggered_direct %>%
select(
usa_atcfid,
geoid,
iso_time,
county_name
) %>%
group_by(usa_atcfid, geoid) %>%
slice_min(iso_time) %>%
ungroup() %>%
left_join(
counties_4326_update
) %>%
st_sf(crs=4326)
triggered <- triggered_direct %>%
unnest("data")%>%
mutate(
trigger = if_else(
geoid == geoid_neighbor,
"direct",
"indirect"
),
county_name = ifelse(
trigger == "indirect",
NA,
county_name
),
geoid = if_else(
geoid == geoid_neighbor,
geoid,
geoid_neighbor
)
) %>%
select(
-geoid_neighbor,
-county_name
) %>%
left_join(
counties_4326_update %>%
tibble() %>%
select(
county_name,
geoid,
county_timezone
)
) %>%
mutate(
local_time = iso_time %>% with_tz(county_timezone)
) %>%
select(
-iso_time
) %>%
group_by(
usa_atcfid,
geoid,
storm_name,
county_name,
county_timezone
) %>%
summarize(
start_local_time = min(local_time),
end_local_time = max(local_time),
) %>%
ungroup() %>%
mutate(
trigger_interval_local_time = interval(start_local_time, end_local_time)
)
triggered_4326 <- triggered %>%
left_join(
counties_4326 %>%
tibble() %>%
select(
geoid,
geometry
)
) %>%
filter(
geoid != 12087.2
) %>%
st_sf(crs=4326)
This code creates as basic map of the hurricane corridor and the triggered counties.
# Map
north_america_4326 <- ne_countries(
continent = 'north america',
returnclass = "sf"
) %>%
st_transform(crs=4326)
ggplot() +
geom_sf(
data = north_america_4326,
fill = "#f7f7f7"
) +
geom_sf(
data = counties_4326,
fill = "#f7f7f7"
) +
geom_sf(
data = triggered_4326,
fill = "#67a9cf"
) +
geom_sf(
data = hull_5070 %>%
st_transform(crs=4326) %>%
st_union() %>%
st_crop(
xmin = triggered_4326 %>%
st_bbox() %>%
pluck(1) - .3,
ymin = triggered_4326 %>%
st_bbox() %>%
pluck(2) - .3,
xmax = triggered_4326 %>%
st_bbox() %>%
pluck(3) + .3,
ymax = triggered_4326 %>%
st_bbox() %>%
pluck(4) + .3,
),
color = "#ef8a62",
alpha = .5,
fill = "#ef8a62",
size = 1,
show.legend = FALSE
) +
geom_sf(
data = triggered_direct_4326_t,
fill = NA
) +
geom_sf(
data = hull_5070 %>%
st_transform(crs=4326) %>%
st_union() %>%
st_crop(
xmin = triggered_4326 %>%
st_bbox() %>%
pluck(1) - .3,
ymin = triggered_4326 %>%
st_bbox() %>%
pluck(2) - .3,
xmax = triggered_4326 %>%
st_bbox() %>%
pluck(3) + .3,
ymax = triggered_4326 %>%
st_bbox() %>%
pluck(4) + .3,
),
color = "#ef8a62",
fill = NA,
size = 1,
show.legend = FALSE
) +
coord_sf(
xlim =
c(
triggered_4326 %>%
st_bbox() %>%
pluck(1),
triggered_4326 %>%
st_bbox() %>%
pluck(3)
),
ylim =
c(
triggered_4326 %>%
st_bbox() %>%
pluck(2),
triggered_4326 %>%
st_bbox() %>%
pluck(4)
)
) +
theme(
panel.background = element_rect(fill = "aliceblue")
) +
ggtitle(
paste0(
"Hurricane ",
hull_5070$storm_name %>% first()
),
subtitle = paste0("HIP-WI County Triggers")
)
This section produces a table that lists all of the triggered counties, along with the county’s trigger period. For a HIP-WI policy to trigger, the policy must be active during some part of the trigger interval.
## Triggered Counties
triggered_4326 %>%
tibble() %>%
mutate(
county_name = county_name %>% str_to_title()
) %>%
select(
county_name,
geoid,
storm_name,
trigger_interval_local_time
) %>%
kbl(
col.names = c("County", "FIP", "Storm Name", "Trigger Interval Local Time")
) %>%
kable_styling(
bootstrap_options = c(
"condensed",
"responsive"
)
)
County | FIP | Storm Name | Trigger Interval Local Time |
---|---|---|---|
Beaufort County | 37013 | Dorian, 2019 | 2019-09-06 02:00:00 EDT–2019-09-06 14:00:00 EDT |
Bertie County | 37015 | Dorian, 2019 | 2019-09-06 08:00:00 EDT–2019-09-06 11:00:00 EDT |
Bladen County | 37017 | Dorian, 2019 | 2019-09-05 20:00:00 EDT–2019-09-06 08:00:00 EDT |
Brunswick County | 37019 | Dorian, 2019 | 2019-09-05 17:00:00 EDT–2019-09-06 08:00:00 EDT |
Camden County | 37029 | Dorian, 2019 | 2019-09-06 08:00:00 EDT–2019-09-06 14:00:00 EDT |
Carteret County | 37031 | Dorian, 2019 | 2019-09-05 23:00:00 EDT–2019-09-06 14:00:00 EDT |
Chowan County | 37041 | Dorian, 2019 | 2019-09-06 08:00:00 EDT–2019-09-06 11:00:00 EDT |
Columbus County | 37047 | Dorian, 2019 | 2019-09-05 17:00:00 EDT–2019-09-06 08:00:00 EDT |
Craven County | 37049 | Dorian, 2019 | 2019-09-05 23:00:00 EDT–2019-09-06 11:00:00 EDT |
Currituck County | 37053 | Dorian, 2019 | 2019-09-06 05:00:00 EDT–2019-09-06 14:00:00 EDT |
Dare County | 37055 | Dorian, 2019 | 2019-09-06 05:00:00 EDT–2019-09-06 14:00:00 EDT |
Duplin County | 37061 | Dorian, 2019 | 2019-09-05 23:00:00 EDT–2019-09-06 08:00:00 EDT |
Gates County | 37073 | Dorian, 2019 | 2019-09-06 08:30:00 EDT–2019-09-06 11:00:00 EDT |
Hyde County | 37095 | Dorian, 2019 | 2019-09-05 23:00:00 EDT–2019-09-06 14:00:00 EDT |
Jones County | 37103 | Dorian, 2019 | 2019-09-05 23:00:00 EDT–2019-09-06 11:00:00 EDT |
Lenoir County | 37107 | Dorian, 2019 | 2019-09-06 02:00:00 EDT–2019-09-06 11:00:00 EDT |
Martin County | 37117 | Dorian, 2019 | 2019-09-06 05:00:00 EDT–2019-09-06 11:00:00 EDT |
New Hanover County | 37129 | Dorian, 2019 | 2019-09-05 17:00:00 EDT–2019-09-06 08:00:00 EDT |
Onslow County | 37133 | Dorian, 2019 | 2019-09-05 23:00:00 EDT–2019-09-06 11:00:00 EDT |
Pamlico County | 37137 | Dorian, 2019 | 2019-09-05 23:00:00 EDT–2019-09-06 14:00:00 EDT |
Pasquotank County | 37139 | Dorian, 2019 | 2019-09-06 08:00:00 EDT–2019-09-06 14:00:00 EDT |
Pender County | 37141 | Dorian, 2019 | 2019-09-05 17:00:00 EDT–2019-09-06 08:00:00 EDT |
Perquimans County | 37143 | Dorian, 2019 | 2019-09-06 08:00:00 EDT–2019-09-06 14:00:00 EDT |
Pitt County | 37147 | Dorian, 2019 | 2019-09-06 02:00:00 EDT–2019-09-06 11:00:00 EDT |
Robeson County | 37155 | Dorian, 2019 | 2019-09-05 17:00:00 EDT–2019-09-06 02:00:00 EDT |
Sampson County | 37163 | Dorian, 2019 | 2019-09-05 23:00:00 EDT–2019-09-06 08:00:00 EDT |
Tyrrell County | 37177 | Dorian, 2019 | 2019-09-06 05:00:00 EDT–2019-09-06 14:00:00 EDT |
Washington County | 37187 | Dorian, 2019 | 2019-09-06 05:00:00 EDT–2019-09-06 14:00:00 EDT |
Wayne County | 37191 | Dorian, 2019 | 2019-09-06 02:00:00 EDT–2019-09-06 05:00:00 EDT |
Berkeley County | 45015 | Dorian, 2019 | 2019-09-05 08:00:00 EDT–2019-09-05 20:00:00 EDT |
Charleston County | 45019 | Dorian, 2019 | 2019-09-05 08:00:00 EDT–2019-09-05 20:00:00 EDT |
Clarendon County | 45027 | Dorian, 2019 | 2019-09-05 11:00:00 EDT–2019-09-05 17:00:00 EDT |
Colleton County | 45029 | Dorian, 2019 | 2019-09-05 08:00:00 EDT–2019-09-05 20:00:00 EDT |
Dillon County | 45033 | Dorian, 2019 | 2019-09-05 17:00:00 EDT–2019-09-06 02:00:00 EDT |
Dorchester County | 45035 | Dorian, 2019 | 2019-09-05 08:00:00 EDT–2019-09-05 20:00:00 EDT |
Georgetown County | 45043 | Dorian, 2019 | 2019-09-05 08:00:00 EDT–2019-09-06 02:00:00 EDT |
Horry County | 45051 | Dorian, 2019 | 2019-09-05 11:00:00 EDT–2019-09-06 05:00:00 EDT |
Marion County | 45067 | Dorian, 2019 | 2019-09-05 11:00:00 EDT–2019-09-06 02:00:00 EDT |
Orangeburg County | 45075 | Dorian, 2019 | 2019-09-05 11:00:00 EDT–2019-09-05 17:00:00 EDT |
Williamsburg County | 45089 | Dorian, 2019 | 2019-09-05 11:00:00 EDT–2019-09-05 20:00:00 EDT |
Chesapeake City | 51550 | Dorian, 2019 | 2019-09-06 08:00:00 EDT–2019-09-06 14:00:00 EDT |
Suffolk City | 51800 | Dorian, 2019 | 2019-09-06 08:30:00 EDT–2019-09-06 11:00:00 EDT |
Virginia Beach City | 51810 | Dorian, 2019 | 2019-09-06 08:00:00 EDT–2019-09-06 14:00:00 EDT |
si <- sessionInfo()
print(si,loadedOnly=T, locale = FALSE)
## R version 4.1.3 (2022-03-10)
## Platform: x86_64-w64-mingw32/x64 (64-bit)
## Running under: Windows 10 x64 (build 19044)
##
## Matrix products: default
##
## attached base packages:
## [1] stats graphics grDevices utils datasets methods base
##
## other attached packages:
## [1] lutz_0.3.1 kableExtra_1.3.4 rnaturalearth_0.1.0
## [4] curl_4.3.2 janitor_2.1.0 units_0.8-0
## [7] geosphere_1.5-14 tigris_1.6.1 sf_1.0-7
## [10] pins_1.0.1 lubridate_1.8.0 forcats_0.5.1
## [13] stringr_1.4.0 dplyr_1.0.9 purrr_0.3.4
## [16] readr_2.1.2 tidyr_1.2.0 tibble_3.1.7
## [19] ggplot2_3.3.6 tidyverse_1.3.1 pacman_0.5.1
##
## loaded via a namespace (and not attached):
## [1] fs_1.5.2 bit64_4.0.5 filelock_1.0.2 webshot_0.5.3
## [5] httr_1.4.3 tools_4.1.3 backports_1.4.1 bslib_0.3.1
## [9] utf8_1.2.2 rgdal_1.5-32 R6_2.5.1 KernSmooth_2.23-20
## [13] DBI_1.1.3 colorspace_2.0-3 withr_2.5.0 sp_1.5-0
## [17] tidyselect_1.1.2 bit_4.0.4 compiler_4.1.3 cli_3.3.0
## [21] rvest_1.0.2 xml2_1.3.3 sass_0.4.1 scales_1.2.0
## [25] classInt_0.4-7 proxy_0.4-27 rappdirs_0.3.3 systemfonts_1.0.4
## [29] digest_0.6.29 foreign_0.8-82 rmarkdown_2.14 svglite_2.1.0
## [33] pkgconfig_2.0.3 htmltools_0.5.2 highr_0.9 dbplyr_2.2.0
## [37] fastmap_1.1.0 rlang_1.0.2 readxl_1.4.0 rstudioapi_0.13
## [41] farver_2.1.0 jquerylib_0.1.4 generics_0.1.2 jsonlite_1.8.0
## [45] vroom_1.5.7 magrittr_2.0.3 s2_1.0.7 Rcpp_1.0.8.3
## [49] munsell_0.5.0 fansi_1.0.3 lifecycle_1.0.1 stringi_1.7.6
## [53] yaml_2.3.5 snakecase_0.11.0 grid_4.1.3 maptools_1.1-4
## [57] parallel_4.1.3 crayon_1.5.1 lattice_0.20-45 haven_2.5.0
## [61] hms_1.1.1 knitr_1.39 pillar_1.7.0 uuid_1.1-0
## [65] wk_0.6.0 reprex_2.0.1 glue_1.6.2 evaluate_0.15
## [69] modelr_0.1.8 vctrs_0.4.1 tzdb_0.3.0 cellranger_1.1.0
## [73] gtable_0.3.0 assertthat_0.2.1 xfun_0.31 broom_0.8.0
## [77] e1071_1.7-11 class_7.3-20 viridisLite_0.4.0 ellipsis_0.3.2
Sys.setenv(TMPDIR=tempdir())
if (!require("pacman")) install.packages("pacman")
pacman::p_install_version("tidyverse", "1.3.1")
pacman::p_load(tidyverse)
pacman::p_load(lubridate)
pacman::p_install_version("pins", "1.0.1")
pacman::p_load(pins)
pacman::p_install_version("sf", "1.0-7")
pacman::p_load(sf)
pacman::p_install_version("tigris", "1.6.1")
pacman::p_load(tigris)
pacman::p_install_version("geosphere", "1.5-14")
pacman::p_load(geosphere)
pacman::p_install_version("units", "0.8-0")
pacman::p_load(units)
pacman::p_install_version("janitor", "2.1.0")
pacman::p_load(janitor)
pacman::p_install_version("curl", "4.3.2")
pacman::p_load(curl)
pacman::p_install_version("rnaturalearth", "0.1.0")
pacman::p_load(rnaturalearth)
pacman::p_install_version("kableExtra", "1.3.4")
pacman::p_load(kableExtra)
pacman::p_install_version("lutz", "0.3.1")
pacman::p_load(lutz)
theme_set(theme_bw())
counties_t <- counties(
state = c(
'01',
'05',
'09',
'10',
'12',
'13',
'15',
'22',
'23',
'24',
'25',
'28',
'33',
'34',
'36',
'37',
'42',
'44',
'45',
'48',
'50',
'51'
),
cb = FALSE,
year = 2020,
progress_bar = FALSE,
class = "sf"
) %>%
mutate(
center_point = st_centroid(geometry),
county_timezone = tz_lookup(center_point, method = "accurate")
) %>%
janitor::clean_names() %>%
select(
namelsad,
geoid,
geometry,
county_timezone
) %>%
rename(
county_name = namelsad
)
counties_4326 <- st_transform(counties_t, crs=4326) %>%
st_sf(crs=4326)
remove(counties_t)
## Altering the Monroe County Florida Shapefile
## "Any part of Monroe County, Florida south of Latitude 25˚ North, as identified by the United States Census Bureau, will not be used for the purpose of determining an adjacent county loss trigger under the Hurricane Insurance Protection-Wind Index Endorsement."
counties_4326_12087 <- counties_4326 %>%
filter(
geoid == "12087"
)
bbox_original_12087 <-st_bbox(counties_4326_12087)
bbox_crop_12087 <- bbox_original_12087
bbox_crop_12087[[2]] <- 25
counties_4326_12087_crop <- st_crop(
counties_4326_12087 ,
bbox_crop_12087
) %>%
mutate(
geometry = geometry %>% st_sfc(crs=4326)
) %>%
st_sf(crs=4326)
counties_4326_12087_psudo <- st_difference(
counties_4326_12087 %>% st_make_valid(),
counties_4326_12087_crop %>% st_make_valid()
) %>%
select(
county_name,
geoid,
geometry,
county_timezone
) %>%
mutate(
county_name = "Monroe Keys County",
geoid = "12087.2",
geoid_neighbor = "12087"
)
## Altering the Honolulu County Shapefile
## "The trailing islands in the state of Hawaii, defined by the United States Census Bureau as Census Tract 114.98 of Honolulu County, shall not constitute a triggered county or county adjacent to a triggered county for purposes of determining a county loss trigger under the Hurricane Insurance Protection-Wind Index Endorsement."
counties_4326_15003 <- counties_4326 %>%
filter(
geoid == "15003"
)
bbox_original_15003 <-st_bbox(counties_4326_15003)
bbox_crop_15003 <- bbox_original_15003
bbox_crop_15003[[4]] <- 22
counties_4326_15003_crop <- st_crop(
counties_4326_15003,
bbox_crop_15003
)
## Updating the County File
counties_4326_update <- counties_4326 %>%
mutate(
geometry = ifelse(
geoid == "12087",
counties_4326_12087_crop$geometry,
ifelse(
geoid == "15003",
counties_4326_15003_crop$geometry,
geometry
)
) %>%
st_sfc(crs=4326)
) %>%
st_sf(crs=4326)
## US Census Bureau County Adjacency File
county_adjacency_pin <- pin("https://www2.census.gov/geo/docs/reference/county_adjacency.txt")
county_adjacency <- read_delim(
county_adjacency_pin,
"\t",
escape_double = FALSE,
trim_ws = TRUE,
col_names = FALSE
) %>%
select(
X2,
X4
) %>%
rename(
geoid = X2,
geoid_neighbor = X4
) %>%
fill(geoid, .direction="down") %>%
group_by(geoid) %>%
nest() %>%
ungroup()
counties_4326_update <- left_join(
counties_4326_update %>%
select(
county_name,
geoid,
county_timezone
),
county_adjacency
) %>%
full_join(
counties_4326_12087_psudo %>%
tibble() %>%
nest(data=c("geoid_neighbor"))
) %>%
drop_na(
geometry,
data
)
counties_5070_update <- counties_4326_update %>% st_transform(crs=5070)
# IBTrACS
ibtracs_shape_zip <- tempfile()
curl_download(
'https://www.ncei.noaa.gov/data/international-best-track-archive-for-climate-stewardship-ibtracs/v04r00/access/shapefile/IBTrACS.since1980.list.v04r00.points.zip',
ibtracs_shape_zip
)
ibtracs_shape_unzip <- tempfile()
unzip(
zipfile = ibtracs_shape_zip,
exdir = ibtracs_shape_unzip
)
remove(ibtracs_shape_zip)
ibtracs_shape <- list.files(
ibtracs_shape_unzip,
pattern = ".shp$",
full.names = TRUE
)
remove(ibtracs_shape_unzip)
ibtracs_4326 <- read_sf(ibtracs_shape) %>%
clean_names() %>%
select(
usa_atcfid,
usa_wind,
usa_pres,
name,
season,
basin,
iso_time,
starts_with("usa_r64"),
track_type
) %>%
filter(
basin %in% c("NA", "EP")
) %>%
mutate(
name = name %>% str_to_title(),
storm_name = str_c(
name,
usa_atcfid %>% str_trunc(4, side = "left", ellipsis = ""),
sep = ", "
) %>%
str_trim(),
season = season %>% as.numeric(),
iso_time = iso_time %>% as_datetime()
) %>%
select(-name) %>%
mutate(
across(
starts_with("usa_r"),
as.numeric
)
) %>%
filter(
storm_name=="Dorian, 2019"
)
remove(ibtracs_shape)
# Constructing Hurricane Corridors
bearing_map <- function(geometry, lon_lead, lat_lead) {
bearing(
st_coordinates(geometry),
c(lon_lead, lat_lead)
) %>%
set_units(degrees)
}
## Another storm can be selected here
points_4326 <- ibtracs_4326 %>%
arrange(iso_time) %>%
group_by(usa_atcfid) %>%
mutate(
lat = map(geometry, 2) %>% unlist(),
lon = map(geometry, 1) %>% unlist(),
lat_lead = lead(lat),
lon_lead = lead(lon),
lat_lag = lag(lat),
lon_lag = lag(lon),
usa_wind_lead = lead(usa_wind),
usa_wind_lag = lag(usa_wind),
point_prior_hu = if_else(
usa_wind_lead >= 64 & usa_wind < 64,
1,
0
),
point_after_hu = if_else(
usa_wind_lag >= 64 & usa_wind < 64,
1,
0
),
hu = if_else(usa_wind >= 64, 1, 0) %>% as_factor,
# Nautical Miles to Meters
wind_extent_hu_m = pmax(
usa_r64_ne,
usa_r64_se,
usa_r64_nw,
usa_r64_sw,
na.rm = T
)*1852,
bearing_accurate = pmap(
.l = list(
geometry=geometry,
lon_lead=lon_lead,
lat_lead=lat_lead
),
.f = bearing_map
)
) %>%
ungroup() %>%
rowwise() %>%
mutate(
distance_to_next = distGeo(
c(lon, lat),
c(lon_lead, lat_lead)
),
wind_extent_hu_m = wind_extent_hu_m %>% replace_na(0)
) %>%
ungroup()
buffers_5070 <- points_4326 %>%
st_transform(crs=5070) %>%
ungroup() %>%
mutate(
geometry = st_buffer(
st_geometry(.),
dist = wind_extent_hu_m,
nQuadSegs = 180
)
) %>%
ungroup()
## Interpolating Hurricane Status Transition Points
### Hurricane Dissolution (end points)
points_4326_e1 <- points_4326 %>%
arrange(iso_time) %>%
group_by(usa_atcfid) %>%
mutate(
lag_wind_extent_hu_m = lag(wind_extent_hu_m),
lag_distance_to_next = lag(distance_to_next),
bearing_accurate = lag(bearing_accurate),
lag_iso_time = lag(iso_time)
) %>%
ungroup() %>%
filter(point_after_hu==1) %>%
mutate(
mid_distance_to_lead = lag_distance_to_next*((usa_wind_lag - 64)/(usa_wind_lag - usa_wind)),
wind_extent_hu_m_guess_last =
pmax(
lag_wind_extent_hu_m/2,
lag_wind_extent_hu_m*(1 -((usa_wind_lag - 64)/(usa_wind_lag - usa_wind)))
),
iso_time = iso_time - minutes(
round(
difftime(
iso_time,
lag_iso_time,
units = "mins"
)*(mid_distance_to_lead/lag_distance_to_next)
)
),
wind_extent_hu_m = wind_extent_hu_m_guess_last,
interpolated_hu = T,
hu = 1 %>% as_factor,
distance_to_next = mid_distance_to_lead,
usa_wind = 64
) %>%
arrange(iso_time) %>%
select(
usa_atcfid,
storm_name,
season,
iso_time,
wind_extent_hu_m,
bearing_accurate,
lon,
lon_lag,
lat,
lat_lag,
usa_wind,
interpolated_hu,
hu,
distance_to_next,
basin
) %>%
ungroup()
points_4326_e2 <- points_4326_e1
for (i in 1:dim(points_4326_e2)[1]) {
points_4326_e2$geometry[i] <- destPoint(
c(
points_4326_e2$lon_lag[i],
points_4326_e2$lat_lag[i]
),
points_4326_e2$bearing_accurate[i],
points_4326_e2$distance_to_next[i]
) %>% st_point() %>% st_sfc()
}
interpolated_end_hu_5070 <- points_4326_e2 %>%
select(
-lat,
-lat_lag,
-lon,
-lon_lag
) %>%
st_transform(crs=5070) %>%
ungroup() %>%
mutate(
geometry = st_buffer(
st_geometry(.),
dist = wind_extent_hu_m,
nQuadSegs = 180
)
) %>%
ungroup()
### Hurricane Inception (start points)
points_4326_s1 <- points_4326 %>%
arrange(iso_time) %>%
group_by(usa_atcfid) %>%
mutate(
lead_wind_extent_hu_m = lead(wind_extent_hu_m),
lead_iso_time = lead(iso_time)
) %>%
filter(point_prior_hu==1) %>%
ungroup() %>%
mutate(
mid_distance_to_lead = distance_to_next*(1-(usa_wind_lead - 64)/(usa_wind_lead - usa_wind)),
wind_extent_hu_m_guess_first =
pmax(
lead_wind_extent_hu_m/2,
lead_wind_extent_hu_m*(1 -((usa_wind_lead - 64)/(usa_wind_lead - usa_wind)))
),
iso_time = iso_time + minutes(
round(
difftime(
lead_iso_time,
iso_time,
units = "mins"
) *(mid_distance_to_lead/distance_to_next)
)
),
wind_extent_hu_m = wind_extent_hu_m_guess_first,
interpolated_hu = T,
hu = 1 %>% as_factor,
distance_to_next = mid_distance_to_lead,
usa_wind = 64,
) %>%
arrange(iso_time) %>%
select(
usa_atcfid,
storm_name,
season,
iso_time,
wind_extent_hu_m,
bearing_accurate,
lon,
lat,
distance_to_next,
usa_wind,
interpolated_hu,
hu,
basin
)
points_4326_s2 <- points_4326_s1
for (i in 1:dim(points_4326_s2)[1]) {
points_4326_s2$geometry[i] <- destPoint(
c(
points_4326_s2$lon[i],
points_4326_s2$lat[i]
),
points_4326_s2$bearing_accurate[i],
points_4326_s2$distance_to_next[i]
) %>% st_point() %>% st_sfc()
}
interpolated_start_hu_5070 <- points_4326_s2 %>%
select(
-lat,
-lon
) %>%
st_transform(crs=5070) %>%
ungroup() %>%
mutate(
geometry = st_buffer(
st_geometry(.),
dist = wind_extent_hu_m,
nQuadSegs = 180
)
) %>%
ungroup()
remove(points_4326)
### Combine Interpolated Data
buffers_5070_new <- buffers_5070 %>%
as_tibble() %>%
mutate(
interpolated_hu = F
) %>%
full_join(
interpolated_start_hu_5070 %>%
as_tibble()
) %>%
full_join(
interpolated_end_hu_5070 %>%
as_tibble()
) %>%
st_sf(crs=5070)
remove(buffers_5070)
### Creating Polygon Pairs
status_change_function <- function(x) {
x <- rle(x)$lengths
rep(seq_along(x), times=x)
}
poly_5070 <- buffers_5070_new %>%
ungroup() %>%
arrange(usa_atcfid, iso_time) %>%
mutate(
hu_status_change = status_change_function(hu %>% as.numeric())
) %>%
group_by(usa_atcfid, hu, hu_status_change) %>%
mutate(
geometry_lag = lag(geometry) %>% st_sfc()
) %>%
slice(2:n()) %>%
ungroup()
geo_union_function <- function(x, y, ...) st_union(x, y)
poly_5070$geometry <- map2(
poly_5070$geometry,
poly_5070$geometry_lag,
geo_union_function
)
poly_5070 <- poly_5070 %>%
select(-geometry_lag) %>%
mutate(
geometry = st_sfc(geometry, crs = 5070)
)
### Convex Hull
hull_5070 <- poly_5070 %>%
group_by(usa_atcfid, iso_time) %>%
mutate(
geometry = st_convex_hull(geometry)
) %>%
ungroup()
remove(poly_5070)
# Finding Triggered Counties
triggered_direct <- st_intersection(
hull_5070,
counties_5070_update %>%
st_make_valid()
) %>%
tibble() %>%
select(-geometry) %>%
arrange(usa_atcfid, iso_time) %>%
group_by(usa_atcfid, geoid) %>%
ungroup() %>%
select(
usa_atcfid,
geoid,
county_name,
data,
storm_name,
season,
iso_time,
interpolated_hu
)
triggered_direct_4326_t <- triggered_direct %>%
select(
usa_atcfid,
geoid,
iso_time,
county_name
) %>%
group_by(usa_atcfid, geoid) %>%
slice_min(iso_time) %>%
ungroup() %>%
left_join(
counties_4326_update
) %>%
st_sf(crs=4326)
triggered <- triggered_direct %>%
unnest("data")%>%
mutate(
trigger = if_else(
geoid == geoid_neighbor,
"direct",
"indirect"
),
county_name = ifelse(
trigger == "indirect",
NA,
county_name
),
geoid = if_else(
geoid == geoid_neighbor,
geoid,
geoid_neighbor
)
) %>%
select(
-geoid_neighbor,
-county_name
) %>%
left_join(
counties_4326_update %>%
tibble() %>%
select(
county_name,
geoid,
county_timezone
)
) %>%
mutate(
local_time = iso_time %>% with_tz(county_timezone)
) %>%
select(
-iso_time
) %>%
group_by(
usa_atcfid,
geoid,
storm_name,
county_name,
county_timezone
) %>%
summarize(
start_local_time = min(local_time),
end_local_time = max(local_time),
) %>%
ungroup() %>%
mutate(
trigger_interval_local_time = interval(start_local_time, end_local_time)
)
triggered_4326 <- triggered %>%
left_join(
counties_4326 %>%
tibble() %>%
select(
geoid,
geometry
)
) %>%
filter(
geoid != 12087.2
) %>%
st_sf(crs=4326)
# Map
north_america_4326 <- ne_countries(
continent = 'north america',
returnclass = "sf"
) %>%
st_transform(crs=4326)
ggplot() +
geom_sf(
data = north_america_4326,
fill = "#f7f7f7"
) +
geom_sf(
data = counties_4326,
fill = "#f7f7f7"
) +
geom_sf(
data = triggered_4326,
fill = "#67a9cf"
) +
geom_sf(
data = hull_5070 %>%
st_transform(crs=4326) %>%
st_union() %>%
st_crop(
xmin = triggered_4326 %>%
st_bbox() %>%
pluck(1) - .3,
ymin = triggered_4326 %>%
st_bbox() %>%
pluck(2) - .3,
xmax = triggered_4326 %>%
st_bbox() %>%
pluck(3) + .3,
ymax = triggered_4326 %>%
st_bbox() %>%
pluck(4) + .3,
),
color = "#ef8a62",
alpha = .5,
fill = "#ef8a62",
size = 1,
show.legend = FALSE
) +
geom_sf(
data = triggered_direct_4326_t,
fill = NA
) +
geom_sf(
data = hull_5070 %>%
st_transform(crs=4326) %>%
st_union() %>%
st_crop(
xmin = triggered_4326 %>%
st_bbox() %>%
pluck(1) - .3,
ymin = triggered_4326 %>%
st_bbox() %>%
pluck(2) - .3,
xmax = triggered_4326 %>%
st_bbox() %>%
pluck(3) + .3,
ymax = triggered_4326 %>%
st_bbox() %>%
pluck(4) + .3,
),
color = "#ef8a62",
fill = NA,
size = 1,
show.legend = FALSE
) +
coord_sf(
xlim =
c(
triggered_4326 %>%
st_bbox() %>%
pluck(1),
triggered_4326 %>%
st_bbox() %>%
pluck(3)
),
ylim =
c(
triggered_4326 %>%
st_bbox() %>%
pluck(2),
triggered_4326 %>%
st_bbox() %>%
pluck(4)
)
) +
theme(
panel.background = element_rect(fill = "aliceblue")
) +
ggtitle(
paste0(
"Hurricane ",
hull_5070$storm_name %>% first()
),
subtitle = paste0("HIP-WI County Triggers")
)
## Triggered Counties
triggered_4326 %>%
tibble() %>%
mutate(
county_name = county_name %>% str_to_title()
) %>%
select(
county_name,
geoid,
storm_name,
trigger_interval_local_time
) %>%
kbl(
col.names = c("County", "FIP", "Storm Name", "Trigger Interval Local Time")
) %>%
kable_styling(
bootstrap_options = c(
"condensed",
"responsive"
)
)
si <- sessionInfo()
print(si,loadedOnly=T, locale = FALSE)