library(shiny)
library(dplyr)
##
## 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(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
library(DT)
##
## Attaching package: 'DT'
## The following objects are masked from 'package:shiny':
##
## dataTableOutput, renderDataTable
# Load the dataset
data <- read.csv("Global_Cybersecurity_Threats_2015-2024.csv", stringsAsFactors = FALSE)
# Data Cleaning (moved outside for better readability)
data <- data %>%
filter(!is.na(Country), !is.na(Year), !is.na(Target.Industry),
!is.na(Number.of.Affected.Users), !is.na(Security.Vulnerability.Type),
!is.na(Attack.Source))
# Define UI
ui <- fluidPage(
titlePanel("Cybersecurity Threats: Affected Users Analysis (2015-2024)"),
sidebarLayout(
sidebarPanel(
selectInput("country", "Select Country:",
choices = c("All", unique(data$Country)), selected = "All"),
selectInput("year", "Select Year:",
choices = c("All", sort(unique(data$Year))), selected = "All"),
selectInput("industry", "Select Target Industry:",
choices = c("All", unique(data$Target.Industry)), selected = "All"),
width = 3
),
mainPanel(
plotlyOutput("jitter_plot", height = "400px"),
plotlyOutput("stacked_area_plot", height = "400px"),
DTOutput("data_table")
)
)
)
# Define server logic
server <- function(input, output) {
# Reactive data filtering
filtered_data <- reactive({
df <- data # Use the cleaned 'data' directly
if (input$country != "All") {
df <- df %>% filter(Country == input$country)
}
if (input$year != "All") {
df <- df %>% filter(Year == as.numeric(input$year))
}
if (input$industry != "All") {
df <- df %>% filter(Target.Industry == input$industry)
}
df
})
# Jitter Plot: Affected Users by Security Vulnerability Type
output$jitter_plot <- renderPlotly({
df <- filtered_data()
p <- ggplot(df, aes(x = Security.Vulnerability.Type, y = Number.of.Affected.Users,
color = Security.Vulnerability.Type)) +
geom_jitter(width = 0.4, alpha = 0.6, size = 3) +
scale_y_log10(labels = scales::comma) +
theme_minimal() +
labs(title = "Affected Users by Security Vulnerability Type (Log Scale)",
x = "Security Vulnerability Type", y = "Number of Affected Users") +
theme(axis.text.x = element_text(angle = 45, hjust = 1),
legend.position = "none") +
scale_color_brewer(palette = "Set2")
ggplotly(p, tooltip = c("x", "y"))
})
# Stacked Area Plot: Cumulative Affected Users by Attack Source Over Time
output$stacked_area_plot <- renderPlotly({
df <- filtered_data()
area_data <- df %>%
group_by(Year, Attack.Source) %>%
summarise(Total_Users = sum(Number.of.Affected.Users), .groups = "drop")
p <- ggplot(area_data, aes(x = Year, y = Total_Users, fill = Attack.Source)) +
geom_area() +
scale_y_continuous(labels = scales::comma) +
theme_minimal() +
labs(title = "Cumulative Affected Users by Attack Source Over Time",
x = "Year", y = "Number of Affected Users") +
scale_fill_brewer(palette = "Set3")
ggplotly(p, tooltip = c("x", "y", "fill"))
})
# Data Table
output$data_table <- renderDT({
datatable(filtered_data(),
options = list(pageLength = 10, autoWidth = TRUE),
rownames = FALSE)
})
}
# Run the application
shinyApp(ui = ui, server = server)
Shiny applications not supported in static R Markdown documents