This project uses interactive maps to explore tornado activity across Oklahoma from 2016 to 2021. Using the leaflet basemap, the maps provide geographic context with satellite imagery, which helps make patterns easier to recognize compared to a plain background. The goal is to understand where tornadoes are most concentrated across counties and how their locations vary over time.
# Filter tornado data to only include years 2016–2021
# This ensures consistency across all maps
tornadopoint_16_21 <- tornadopoint %>%
filter(yr >= 2016 & yr <= 2021) %>%
select(om, yr, date)
# Spatial join: assign each tornado point to a county
countytornado <- st_join(tornadopoint_16_21, county)
# Remove geometry to allow summarizing (we only need attributes here)
countytornado <- st_drop_geometry(countytornado)
# Count number of tornadoes per county per year
countytornadosum <- countytornado %>%
group_by(GEOID, NAME, yr) %>%
summarize(tornadoct = n(), .groups = "drop")
# Join summarized tornado counts back to county polygons
countymap <- county %>%
left_join(countytornadosum, by = c("GEOID", "NAME")) %>%
# Calculate and add area
mutate(area = st_area(geometry),
# Calculate tornado density (tornadoes per 1000 km²)
tornadodensity = 10^6 * 10^3 * tornadoct / area) %>%
# Remove rows with missing values
drop_na() %>%
# Remove units so ggplot can use the values
drop_units()
# This map uses a leaflet satellite basemap (Esri imagery), which provides real world geographic context such as land cover and terrain. On top of this basemap, counties are colored based on tornado density (Part B)
leaflet(data = countymap) %>%
# adds background map from ESRI
addProviderTiles(providers$Esri.WorldImagery) %>%
addPolygons(
fillColor = ~colorNumeric("YlOrRd", tornadodensity)(tornadodensity),
color = "black",
weight = 1,
fillOpacity = 0.7,
label = ~NAME
) %>%
addPolygons(
data = county,
# no fill
fill = FALSE,
# boundary color
color = "black",
weight = 3
)%>%
addMeasure() %>%
addGraticule() %>%
addMiniMap(position = "bottomleft") %>%
leafem::addMouseCoordinates() %>%
addLegend(colorBin("YlOrRd", countymap$tornadodensity, bins = 5),countymap$tornadodensity,
title = "Tornado Density",
position = "bottomleft",
)
## Warning: sf layer has inconsistent datum (+proj=longlat +datum=NAD83 +no_defs).
## Need '+proj=longlat +datum=WGS84'
## Warning: sf layer has inconsistent datum (+proj=longlat +datum=NAD83 +no_defs).
## Need '+proj=longlat +datum=WGS84'
# This map also uses the leaflet basemap, but instead of aggregated values, it shows individual tornado events as points for each year (2016-2021) (Part B)
leaflet(data = tornadopoint_16_21) %>%
# adds background map from ESRI
addProviderTiles(providers$Esri.WorldImagery) %>%
addCircles(
fillColor = ~colorFactor("Set1", yr)(yr),
color = "black",
radius = 5000,
weight = 2,
fillOpacity = 0.7
) %>%
addPolygons(
data = county,
# no fill
fill = FALSE,
# boundary color
color = "black",
weight = 3,
label = ~NAME
)%>%
addMeasure() %>%
addGraticule() %>%
addMiniMap(position = "bottomleft") %>%
leafem::addMouseCoordinates() %>%
addLegend(
pal = colorFactor("Set1", tornadopoint_16_21$yr),
values = ~yr,
title = "Tornado Distribution by Year",
position = "bottomleft"
)
## Warning: sf layer has inconsistent datum (+proj=longlat +datum=NAD83 +no_defs).
## Need '+proj=longlat +datum=WGS84'
## Warning: sf layer has inconsistent datum (+proj=longlat +datum=NAD83 +no_defs).
## Need '+proj=longlat +datum=WGS84'
Looking at both maps, tornado activity is not spread evenly across Oklahoma. Some counties clearly have more tornadoes than others. From the density map, most of the higher values are in central and eastern parts of the state, while western areas tend to have lower density. The tornado location map shows a similar pattern. The points are spread across the state, but there are more clusters in the same central and eastern regions. This means those areas experience tornadoes more often over time. Using the leaflet basemap also helps make this easier to see because it shows the real landscape underneath, instead of just a plain background.