library(readr)
cyber_events_2026_02_13 <- read_csv("cyber_events_2026-02-13.csv")
## Rows: 16382 Columns: 46
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (24): country, change_log, county, description, industry, event_subtype,...
## dbl (22): oecd, year, csto, industry_code, opec, five_eyes, gulf_coop, shang...
##
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
cyber_events <- cyber_events_2026_02_13
## [1] "Oklahoma" NA "Texas" "Connecticut"
## [5] "Undetermined" "Minnesota" "Oregon" "New York"
## [9] "Illinois" "Washington D.C." "California" "Delaware"
## [13] "Florida" "Massachusetts" "Pennsylvania" "Alaska"
## [17] "Arkansas" "Georgia" "North Carolina" "Missouri"
## [21] "Virginia" "Rhode Island" "Alabama" "Tennessee"
## [25] "Puerto Rico" "Ohio" "Kansas" "Maryland"
## [29] "New Jersey" "Kentucky" "Michigan" "Washington"
## [33] "Colorado" "Louisiana" "New Mexico" "Arizona"
## [37] "Indiana" "Nevada" "South Carolina" "Hawaii"
## [41] "Wisconsin" "Idaho" "Maine" "Utah"
## [45] "New Hampshire" "West Virginia" "Iowa" "Nebraska"
## [49] "Wyoming" "Virgin Islands" "Mississippi" "North Dakota"
## [53] "Vermont" "South Dakota" "Montana" "Guam"
## [57] "undetermined"
library(dplyr)
## Warning: package 'dplyr' was built under R version 4.3.3
##
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
library(ggplot2)
library(maps)
## Warning: package 'maps' was built under R version 4.3.3
# Clean state names
cyber_clean <- cyber_events %>%
filter(!is.na(state),
state != "Undetermined",
state != "undetermined") %>%
mutate(state = tolower(state),
state = ifelse(state == "washington d.c.", "district of columbia", state))
# Count frequency
state_counts <- cyber_clean %>%
count(state)
states_map <- map_data("state")
map_data_joined <- states_map %>%
left_join(state_counts, by = c("region" = "state"))
ggplot(map_data_joined, aes(x = long, y = lat, group = group, fill = n)) +
geom_polygon(color = "black") +
coord_fixed(1.3) +
scale_fill_gradient(low = "lightyellow", high = "darkred", na.value = "white") +
theme_void() +
labs(title = "Cyber Attack Events by State",
fill = "Frequency")

state_summary <- cyber_clean %>%
group_by(state) %>%
summarise(
n = n(),
first_event = min(event_date, na.rm = TRUE),
last_event = max(event_date, na.rm = TRUE)
)
map_data_joined <- states_map %>%
left_join(state_summary, by = c("region" = "state"))
map_data_joined$hover_text <- paste0(
"State: ", map_data_joined$region,
"<br>Events: ", map_data_joined$n,
"<br>First Event: ", map_data_joined$first_event,
"<br>Last Event: ", map_data_joined$last_event
)
library(plotly)
##
## Attaching package: 'plotly'
## The following object is masked from 'package:ggplot2':
##
## last_plot
## The following object is masked from 'package:stats':
##
## filter
## The following object is masked from 'package:graphics':
##
## layout
p <- ggplot(map_data_joined,
aes(x = long, y = lat, group = group, fill = n, text = hover_text)) +
geom_polygon(color = "black") +
coord_fixed(1.3) +
scale_fill_distiller(palette = "YlOrRd", direction = 1, na.value = "white") +
theme_void() +
labs(title = "Cyber Events by State From 2014 to February 13, 2026",
fill = "Frequency")
ggplotly(p, tooltip = "text")