all_crime <- read_excel("all_crime_data.xlsx", sheet=6)
data2 <- all_crime %>%
select(state, year, population, gambling, drugs, auto_theft, petty_theft, larceny,
fraud, sexual_assault, human_trafficking, assaults, homicide, prostitution1,
weapon_law_violations, pornography, sports_tampering, animal_cruelty,
robbery, hacking, blackmail, embezzlement, vandalism, forgery, burgulary, bribery,
arson, abduction)
data2 <- data2 %>%
group_by(state) %>%
mutate(across(gambling:abduction, ~replace(., is.na(.), 0))) %>% # Replace NAs with 0
mutate(total_crime = rowSums(across(gambling:abduction), na.rm = TRUE)) %>%
mutate(total_crime_per_capita = total_crime / population) %>%
ungroup()
Total Crime in the Continental United States
var divElement = document.getElementById('viz1733513784279');
var vizElement = divElement.getElementsByTagName('object')[0];
if ( divElement.offsetWidth > 800 )
{ vizElement.style.width='1000px';vizElement.style.height='827px';}
else if ( divElement.offsetWidth > 500 )
{ vizElement.style.width='1000px';vizElement.style.height='827px';}
else { vizElement.style.width='100%';vizElement.style.height='827px';}
var scriptElement = document.createElement('script');
scriptElement.src = 'https://public.tableau.com/javascripts/api/viz_v1.js';
vizElement.parentNode.insertBefore(scriptElement, vizElement);
Crime Trends Per Capita Mapper
# Summarize crime data for total crime per capita
crime_summary_per_capita <- data2 %>%
filter(year %in% c(2020, 2021, 2022, 2023), !is.na(total_crime_per_capita)) %>%
group_by(state, year) %>%
summarise(total_crime_per_capita = sum(total_crime_per_capita, na.rm = TRUE))
## `summarise()` has grouped output by 'state'. You can override using the
## `.groups` argument.
# Compare total crime per capita between 2020 and 2023, filling missing years
crime_comparison_per_capita <- crime_summary_per_capita %>%
mutate(year = as.character(year)) %>% # Ensure `year` is a character
complete(year = c("2020", "2021", "2022", "2023"), fill = list(total_crime_per_capita = NA)) %>% # Ensure all years are present
spread(key = year, value = total_crime_per_capita) %>% # Spread into wide format
rename(
crime_2020 = `2020`,
crime_2021 = `2021`,
crime_2022 = `2022`,
crime_2023 = `2023`
) %>%
mutate(
adjusted_crime_2020 = case_when(
!is.na(crime_2020) ~ crime_2020,
is.na(crime_2020) & !is.na(crime_2021) ~ crime_2021,
is.na(crime_2020) & is.na(crime_2021) & !is.na(crime_2022) ~ crime_2022,
TRUE ~ crime_2023 # Default to 2023 if all others are missing
),
crime_pctdiff = ((crime_2023 - adjusted_crime_2020) / adjusted_crime_2020) * 100
)
# If percent difference is NA (no data for a state), replace with 0
crime_comparison_per_capita <- crime_comparison_per_capita %>%
mutate(crime_pctdiff = ifelse(is.na(crime_pctdiff), 0, crime_pctdiff))
crime_comparison_per_capita <- crime_comparison_per_capita %>%
mutate(
hover_label = paste("State: ", state,
"<br>\nPercent Change in Crimes per Capita: ",
round(crime_pctdiff, 3), "%")
)
# Plotting the map with percent change in crime per capita
p_per_capita <- plot_usmap(data = crime_comparison_per_capita,
values = "crime_pctdiff",
regions = "states",
labels = FALSE) + # Add state abbreviations
scale_fill_gradientn(
colors = c("lightblue", "white", "orange", "red"),
values = c(0, 0.25, 0.5, 1),
limits = c(-100, 700),
name = "Crime % Change (per capita)"
) +
theme(legend.position = "right") +
labs(
title = "Percent Change in Crime Rates Per Capita (2020-2023)",
) +
theme(
legend.position = "right",
plot.title = element_text(size=14, face="bold", hjust=0.5),
plot.caption = element_text(size = 9, hjust = 0, margin = margin(t = 10))
)
# Add a custom caption below the plot
interactive_map_per_capita <- ggplotly(p_per_capita, tooltip = c("hover_label", "crime_pctdiff")) %>%
layout(
annotations = list(
x = 0.5, # Position on the x-axis (center)
y = -0.1, # Position on the y-axis (below the plot)
showarrow = FALSE,
font = list(size = 10, color = "black"),
xref = "paper", yref = "paper",
align = "center"
)
)
interactive_map_per_capita
State of Crime: A Stacked Perspective
var divElement = document.getElementById('viz1732592196232');
var vizElement = divElement.getElementsByTagName('object')[0]; vizElement.style.width='100%';vizElement.style.height=(divElement.offsetWidth*0.75)+'px';
var scriptElement = document.createElement('script');
scriptElement.src = 'https://public.tableau.com/javascripts/api/viz_v1.js'; v
izElement.parentNode.insertBefore(scriptElement, vizElement);
violent_crimes <- data2[, c("state", "year", "assaults", "homicide", "robbery",
"sexual_assault", "human_trafficking", "animal_cruelty",
"arson", "abduction")]
non_violent_crimes <- data2[, c("state", "year", "larceny", "fraud", "embezzlement",
"petty_theft", "gambling", "auto_theft", "prostitution1",
"sports_tampering", "blackmail", "hacking",
"vandalism", "forgery")]
violent_sums <- rowSums(violent_crimes[, 3:ncol(violent_crimes)], na.rm = TRUE)
non_violent_sums <- rowSums(non_violent_crimes[, 3:ncol(non_violent_crimes)], na.rm = TRUE)
crime_comparison <- data.frame(
State = data2$state,
Violent = violent_sums,
NonViolent = non_violent_sums,
Assaults = data2$assaults,
Homicide = data2$homicide,
Robbery = data2$robbery,
Sexual_Assault = data2$sexual_assault,
Human_Trafficking = data2$human_trafficking,
Animal_Cruelty = data2$animal_cruelty,
Arson = data2$arson,
Abduction = data2$abduction,
Larceny = data2$larceny,
Fraud = data2$fraud,
Embezzlement = data2$embezzlement,
Petty_Theft = data2$petty_theft,
Gambling = data2$gambling,
Auto_Theft = data2$auto_theft,
Prostitution = data2$prostitution1,
Sports_Tampering = data2$sports_tampering,
Blackmail = data2$blackmail,
Hacking = data2$hacking,
Vandalism = data2$vandalism,
Forgery = data2$forgery
)
crime_comparison_long <- crime_comparison %>%
pivot_longer(
cols = -c(State, Violent, NonViolent),
names_to = "Crime_Type",
values_to = "Count"
)
crime_comparison_long <- crime_comparison_long %>%
mutate(Crime_Category = ifelse(Crime_Type %in% c("Assaults", "Homicide", "Robbery", "Sexual_Assault",
"Human_Trafficking", "Animal_Cruelty", "Arson", "Abduction"),
"Violent Crimes", "Non-Violent Crimes"))
High Stakes: Tracking Drug Offenses Across the States
var divElement = document.getElementById('viz1732592249226');
var vizElement = divElement.getElementsByTagName('object')[0];
if ( divElement.offsetWidth > 800 ) { vizElement.style.width='1000px';vizElement.style.height='827px';}
else if ( divElement.offsetWidth > 500 ) { vizElement.style.width='1000px';vizElement.style.height='827px';}
else { vizElement.style.width='100%';vizElement.style.height='777px';}
var scriptElement = document.createElement('script');
scriptElement.src = 'https://public.tableau.com/javascripts/api/viz_v1.js';
vizElement.parentNode.insertBefore(scriptElement, vizElement);
df_long <- all_crime %>%
select(state, year, population, drug_offenses) %>%
pivot_longer(cols = starts_with("drug_offenses"), names_to = "variable", values_to = "value") %>%
mutate(per_capita = value / population)
# Get map data for US states
us_map <- map_data("state")
us_map <- us_map %>%
rename(state = region)
# Merge the map data with your dataset (make sure state names match)
df_long$state <- tolower(df_long$state)
# Merge map data with your dataset
df_map_data <- merge(us_map, df_long, by = "state", all.x = TRUE)
https://prm4dq.shinyapps.io/interactive_map/
Highs and Lows: Regional Drug Density
df_avg_dot <- df_long %>%
filter(year >= 2020 & year <= 2023) %>%
group_by(state) %>%
summarise(avg_per_capita = mean(per_capita, na.rm = TRUE),
avg_population = mean(population, na.rm = TRUE)) %>%
ungroup()
regions <- list(
new_england = c("connecticut", "maine", "massachusetts", "new hampshire", "rhode island", "vermont"),
great_plains = c("kansas", "nebraska", "north dakota", "south dakota", "oklahoma"),
rocky_mountains = c("colorado", "idaho", "montana", "utah", "wyoming"),
mid_atlantic = c("delaware", "maryland", "new jersey", "new york", "pennsylvania", "virginia", "west virginia"),
south = c("alabama", "arkansas", "florida", "georgia", "kentucky", "louisiana", "mississippi", "north carolina", "south carolina", "tennessee", "texas"),
west_coast = c("california", "oregon", "washington"),
midwest = c("illinois", "indiana", "iowa", "michigan", "minnesota", "missouri", "ohio", "wisconsin"),
southwest = c("arizona", "new mexico", "nevada"),
alaska = c("alaska"),
hawaii = c("hawaii")
)
df_avg_density <- df_avg_dot %>%
mutate(region = case_when(
state %in% regions$new_england ~ "new england",
state %in% regions$great_plains ~ "great plains",
state %in% regions$rocky_mountain ~ "rocky mountains",
state %in% regions$mid_atlantic ~ "mid atlantic",
state %in% regions$south ~ "south",
state %in% regions$west_coast ~ "west coast",
state %in% regions$midwest ~ "midwest",
state %in% regions$southwest ~ "southwest",
state %in% regions$alaska ~ "alaska",
state %in% regions$hawaii ~ "hawaii",
TRUE ~ "other"
))
gg_density_region <- ggplot(df_avg_density, aes(x = avg_per_capita * 100000, fill = region)) +
geom_density(alpha = 0.7, color = "black", size = 0.3) +
scale_fill_viridis(discrete = T, option = "inferno", name = NULL) +
labs(
title = "Density of Average Drug Offenses by Region (2020-2023)",
subtitle = "Based on average drug offenses per 100,000 people",
x = "Average Drug Offenses per 100,000 People",
y = "Density",
fill = "Region"
) +
theme_minimal(base_size = 14) +
theme(
plot.title = element_text(face = "bold", size = 16, hjust = 0.5),
plot.subtitle = element_text(face = "italic", size = 12, hjust = 0.5),
legend.position = "bottom",
legend.title = element_blank(),
legend.key.size = unit(0.8, "cm"),
axis.text = element_text(size = 12),
axis.title = element_text(face = "bold"),
axis.title.y = element_text(margin = margin(r = 15)),
axis.title.x = element_text(margin = margin(t = 10))
) +
scale_x_continuous(expand = c(0, 0)) +
scale_y_continuous(expand = c(0, 0))
ggplotly(gg_density_region) %>%
layout(width = 1000,
height = 500,
legend = list(orientation = "h", x = 0.5, xanchor = "center", y = -0.2) # Move legend explicitly in Plotly
)
Breaking Down Crime: The Hidden Connections Between Drug Offenses and Crime Trends
long_data <- data2 %>%
pivot_longer(cols = c(larceny, auto_theft, petty_theft, assaults, homicide, robbery, burgulary, sexual_assault, animal_cruelty, abduction, arson, vandalism),
names_to = "crime_type",
values_to = "crime_count")
correlation_summary <- long_data %>%
group_by(crime_type) %>%
summarise(
correlation = cor(drugs, crime_count, use = "complete.obs"),
.groups = 'drop'
) %>%
arrange(desc(correlation))
facet_plot <- ggplot(long_data, aes(x = drugs, y = crime_count)) +
geom_point(aes(text = paste("State: ", state, "<br>Drug Offenses: ", drugs, "<br>Crime: ", crime_count))) +
geom_smooth(method = "lm", color = "blue", se = TRUE) +
facet_wrap(~ crime_type, scales = "free_y", ncol = 3) +
labs(title = "Drug Offenses vs Various Crimes", x = "Drug Offenses", y = "Crime Count") +
scale_y_continuous(labels = label_number(scale = 1)) +
scale_x_continuous(labels = label_number(scale = 1)) +
theme_minimal() +
theme(
strip.text = element_text(size = 10),
axis.text.x = element_text(angle = 45, hjust = 1),
axis.title.x = element_text(margin = margin(t = 20)),
axis.title.y = element_text(margin = margin(r = 20))
)
interactive_facet_plot <- ggplotly(facet_plot, tooltip = "text")
## `geom_smooth()` using formula = 'y ~ x'
interactive_facet_plot <- interactive_facet_plot %>% layout(
width = 1200,
height = 800,
margin = list(l = 100, r = 100, t = 100, b = 100)
)
interactive_facet_plot
summary_table <- ggplot(correlation_summary, aes(x = crime_type, y = correlation)) +
geom_bar(stat = "identity", fill = "lightblue") +
geom_text(aes(label = round(correlation, 2)), vjust = -0.5) +
labs(title = "Correlation Between Drug Offenses and Crimes",
x = "Crime Type",
y = "Correlation Coefficient") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, hjust = 1))
summary_table

Highs and Lows: Visualizing Marijuana Laws and Drug Trends
weed <- read_excel("weed_laws.xlsx")
weed_merged <- merge(data2, weed, by = "state", all.x = TRUE)
weed_merged <- weed_merged %>%
mutate(legalized_marijuana = case_when(
legal_status == "legal" ~ "Legal",
legal_status == "mixed" ~ "Mixed",
TRUE ~ "Illegal"
))
weed_merged <- weed_merged %>%
mutate(hover_text = paste(state,
"\nLegal Status: ", legal_status,
"\nDecriminalized: ", decriminalized))
violin_plot <- ggplot(weed_merged, aes(x = legalized_marijuana, y = drugs, fill = legalized_marijuana)) +
geom_violin(trim = FALSE, color = "black") +
labs(title = "Distribution of Drug Offenses by Marijuana Legalization Status",
subtitle = "Comparison across 'Legal', 'Mixed', and 'Illegal' States",
x = "Marijuana Legalization Status", y = "Drug Offenses") +
theme_minimal(base_size = 15) +
scale_fill_manual(values = c("Legal" = "forestgreen", "Mixed" = "goldenrod", "Illegal" = "firebrick")) +
scale_y_continuous(labels = label_comma()) +
theme(axis.title = element_text(size = 10), axis.text = element_text(size = 10),
plot.title = element_text(size = 12, face = "bold"), plot.subtitle = element_text(size = 14, face = "italic")) +
theme(legend.position = "top") +
guides(fill = guide_legend(title = "Legalization Status"))
plotly_violin <- ggplotly(violin_plot)
plotly_violin
boxplot_plot <- ggplot(weed_merged, aes(x = decriminalized, y = drugs, fill = decriminalized)) +
geom_boxplot(outlier.colour = "red", outlier.size = 2, color = "black") +
labs(title = "Comparison of Drug Offenses in Decriminalized vs Non-Decriminalized States",
subtitle = "States with Decriminalized Marijuana vs Others",
x = "Decriminalization Status", y = "Drug Offenses") +
theme_minimal(base_size = 15) +
scale_fill_manual(values = c("yes" = "cornflowerblue", "no" = "gray")) +
scale_y_continuous(labels = label_comma()) +
theme(axis.title = element_text(size = 10), axis.text = element_text(size = 10),
plot.title = element_text(size = 12, face = "bold"), plot.subtitle = element_text(size = 14, face = "italic")) +
theme(legend.position = "top") +
guides(fill = guide_legend(title = "Decriminalized?"))
# Convert to plotly
plotly_boxplot <- ggplotly(boxplot_plot)
plotly_boxplot