Introduction

This report presents an analysis of tornado occurrences in Oklahoma, visualizing tornado paths, summarizing tornado densities, and examining spatial patterns.

Load and Prepare Data

Loads and formats the data.

okcounty <- st_read("M:/SCHOOL/PennState/GEO_588_2025/LESSON_4/DATA/Chapter5/Chapter5/ok_counties.shp", quiet = TRUE)
tpoint <- st_read("M:/SCHOOL/PennState/GEO_588_2025/LESSON_4/DATA/Chapter5/Chapter5/ok_tornado_point.shp", quiet = TRUE)
tpath <- st_read("M:/SCHOOL/PennState/GEO_588_2025/LESSON_4/DATA/Chapter5/Chapter5/ok_tornado_path.shp", quiet = TRUE)

tpoint <- st_transform(tpoint, st_crs(okcounty))
tpath <- st_transform(tpath, st_crs(okcounty))

Tornado Paths and Points Visualization

This code filters tornado data from 2016 to 2021 and prepares two datasets: one for tornado points and another for tornado paths. It then creates two maps using ggplot2 and sf, where the first map plots tornado points in Viridis color, and the second maps tornado paths, colored by year using a Viridis discrete palette. Finally, both maps are combined into a side-by-side visualization using plot_grid().

tpoint_16_21 <- tpoint %>%
  filter(yr >= 2016 & yr <= 2021) %>%
  select(om, yr, date)

tpath_16_21 <- tpath %>%
  filter(yr >= 2016 & yr <= 2021) %>%
  select(om, yr, date)

# Map tornado points
tornado_points_map <- ggplot() +
  geom_sf(data = okcounty, fill = NA) +
  geom_sf(data = tpoint_16_21, color = viridis(1)) +  
  theme_bw()

# Map tornado paths
tornado_paths_map <- ggplot() +
  geom_sf(data = okcounty, fill = NA) +
  geom_sf(data = tpath_16_21, aes(color = as.factor(yr)), size = 1) +
  scale_color_viridis_d(name = "Year") +  
  theme_bw()

# Combine maps
plot_grid(tornado_points_map, tornado_paths_map, ncol = 2)

Tornado Density Analysis

This section calculates tornado density per county from 2016 to 2021 by joining tornado points with county boundaries and counting tornado occurrences per county and year. It then computes tornado density by normalizing the count over the county area and visualizes it using a faceted density map, where each facet represents a different year.

# Join tornado points with county boundaries
countypnt <- st_join(tpoint_16_21, okcounty) %>% st_drop_geometry()

# Summarize tornado count per county per year
countysum <- countypnt %>%
  group_by(GEOID, yr) %>%
  summarize(tcnt = n(), .groups = "drop")

# Calculate tornado density per county
countymap <- okcounty %>%
  left_join(countysum, by = "GEOID") %>%
  mutate(tcnt = replace_na(tcnt, 0),
         area = st_area(.),
         tdens = 10^6 * 10^3 * tcnt / area) %>%
  drop_units()

# Create faceted density map
faceted_density_plot <- ggplot(countymap) +
  geom_sf(aes(fill = tdens), color = "black") +
  facet_wrap(~yr) +
  scale_fill_viridis_c(name = "Density", trans = "sqrt", na.value = "white") +  # Viridis used
  theme_void()

print(faceted_density_plot)

Choropleth Maps with Quantile Breaks

This part creates choropleth maps to visualize tornado density across counties using different numbers of classification bins (3, 4, 5, and 6 classes). It loops through each classification scheme, applies quantile-based binning to categorize tornado density, and maps the results. Then, the generated maps are combined into a composite figure using plot_grid(), allowing for easy comparison of different classification schemes.

break_classes <- c(3, 4, 5, 6)
choropleth_maps <- list()

for (i in seq_along(break_classes)) {
  n_classes <- break_classes[i]
  qbrks <- classIntervals(countymap$tdens, n_classes, style = "quantile")$brks
  countymap <- countymap %>%
    mutate(tdens_cat = cut(tdens, breaks = qbrks, include.lowest = TRUE))
  
  choropleth_maps[[i]] <- ggplot(countymap) +
  geom_sf(aes(fill = tdens_cat), color = "black") +
  scale_fill_viridis_d(option = "viridis", na.value = "white") + 
  labs(title = paste("Tornado Density (", n_classes, " Classes)", sep = ""), fill = "Category") +
  theme_minimal() +
  theme(plot.title = element_text(hjust = .7))  

}

# Combine maps into a composite figure
plot_grid(plotlist = choropleth_maps, ncol = 2)

Part B: Interactive Leaflet Map

This code creates an interactive Leaflet map displaying tornado occurrences from 2016 to 2021 using Viridis colors. It defines a color palette that maps tornado years to distinct colors, then adds circle markers for each tornado, with interactive hover labels and popups. A legend is placed in the bottom right corner, ensuring users can easily interpret the tornado year color coding.

tpoint_16_21 <- tpoint_16_21 %>%
  st_transform(crs = 4326)

pal <- colorFactor(viridis_pal(option = "viridis")(length(unique(tpoint_16_21$yr))), 
                   domain = tpoint_16_21$yr)

leaflet(tpoint_16_21) %>%
  addTiles() %>%  
  addCircleMarkers(
    radius = 5,  
    color = ~pal(yr),  
    label = ~paste("Tornado on", date), 
    popup = ~paste("Year:", yr, "<br>Occurrence:", om)  
  ) %>%
  addLegend(
    "bottomright",  
    pal = pal,  
    values = tpoint_16_21$yr,  
    title = "Tornado Year",  
    opacity = 1  
  )

Conclusion

This report provides an overview of tornado patterns in Oklahoma using both static and interactive mapping techniques. By visualizing tornado paths and densities, we gain insights into their spatial distribution, while the interactive map allows for deeper exploration of specific occurrences. These tools help in understanding tornado frequency, clustering, and trends over time.

Source:https://bookdown.org/mcwimberly/gdswr-book/vector-geospatial-data.html