Instruction
Story - 3 : Do stricter gun laws reduce firearm gun deaths?
The CDC publishes firearm mortality for each State per 100,000 persons https://www.cdc.gov/nchs/pressroom/sosmap/firearm_mortality/firearm.htm. Each State’ firearm control laws can be categorized as very strict to very lax. The purpose of this Story is to answer the question, ” Do stricter firearm control laws help reduce firearm mortality?”
For this assignment you will need to:
Access the firearm mortality data from the CDC using an available API (https://open.cdc.gov/apis.html)
Create a 5 point Likert scale categorizing gun control laws from most lax to strictest and assign each state to the most appropriate Likert bin.
Determine wether stricter gun control laws result in reduced gun violence deaths
Present your story using heat maps
In this story, Gun violence continues to pose a serious and multifaceted public health challenge in the United States. Each year, thousands of lives are lost to firearms through homicides, suicides, and accidental shootings—making firearm-related deaths a leading cause of preventable mortality. While many social, cultural, and economic factors contribute to this issue, the role of gun legislation remains one of the most heavily debated aspects of the conversation. For decades, policymakers and researchers have sought to understand whether the strength of state firearm laws influences rates of gun-related deaths.
This objective of this analysis examines how variations in gun control strictness across states relate to firearm mortality rates, using recent data published by the Centers for Disease Control and Prevention (CDC). States are categorized on a five-point scale ranging from least to most restrictive firearm policies. Through the use of heat maps and comparative visualizations, the study aims to highlight potential trends between legislative strictness and mortality outcomes. Ultimately, this data-driven exploration seeks to offer insight into how differences in firearm policy may shape public safety and impact lives across the United States.
library(tidyverse)
library(httr)
library(jsonlite)
library(ggplot2)
library(tidyr)
library(usmap)
library(gridExtra)
library(kableExtra)
library(plotly)
library(dplyr)
library(ggrepel)
Load the data
The dataset in this section comes directly from the CDC’s public
API, providing the latest firearm mortality data. The information is
automatically converted from JSON into a DataFrame, making it easier to
analyze and visualize while ensuring consistency and
reproducibility.
Access the firearm mortality data from the CDC using an available API (https://open.cdc.gov/apis.html)
url <- "https://data.cdc.gov/resource/489q-934x.json"
response <- GET(url)
data <- content(response, as = "text")
df <- as.data.frame(fromJSON(data))
# View data
kable(head(df), "simple")
year_and_quarter | time_period | cause_of_death | rate_type | unit | rate_overall | rate_sex_female | rate_sex_male | rate_alaska | rate_alabama | rate_arkansas | rate_arizona | rate_california | rate_colorado | rate_connecticut | rate_district_of_columbia | rate_delaware | rate_florida | rate_georgia | rate_hawaii | rate_iowa | rate_idaho | rate_illinois | rate_indiana | rate_kansas | rate_kentucky | rate_louisiana | rate_massachusetts | rate_maryland | rate_maine | rate_michigan | rate_minnesota | rate_missouri | rate_mississippi | rate_montana | rate_north_carolina | rate_north_dakota | rate_nebraska | rate_new_hampshire | rate_new_jersey | rate_new_mexico | rate_nevada | rate_new_york | rate_ohio | rate_oklahoma | rate_oregon | rate_pennsylvania | rate_rhode_island | rate_south_carolina | rate_south_dakota | rate_tennessee | rate_texas | rate_utah | rate_virginia | rate_vermont | rate_washington | rate_wisconsin | rate_west_virginia | rate_wyoming | rate_age_1_4 | rate_age_5_14 | rate_age_15_24 | rate_age_25_34 | rate_age_35_44 | rate_age_45_54 | rate_age_55_64 | rate_65_74 | rate_age_75_84 | rate_age_85_plus |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
2022 Q1 | 12 months ending with quarter | All causes | Age-adjusted | Deaths per 100,000 | 873.2 | 729.4 | 1038 | 944.5 | 1109.8 | 1097.1 | 882.5 | 719.5 | 808.2 | 725.9 | 844.4 | 868.3 | 828 | 973.6 | 647.1 | 860.8 | 892.8 | 839.4 | 1011.9 | 938.4 | 1153.2 | 1084.4 | 717 | 800.3 | 910.3 | 956.2 | 771.6 | 986.6 | 1193.4 | 925.3 | 952.8 | 810.5 | 839.4 | 791.9 | 723.5 | 1007.9 | 933.3 | 694.4 | 1019.8 | 1126.4 | 875.6 | 893.5 | 771 | 1022 | 871.4 | 1122.6 | 918.3 | 822.2 | 860.1 | 800.5 | 811.1 | 857.1 | 1239.9 | 956.8 | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA |
2022 Q1 | 12 months ending with quarter | Alzheimer disease | Age-adjusted | Deaths per 100,000 | 30.6 | 35 | 23.8 | 28.5 | 45.5 | 43.2 | 29.6 | 38.4 | 32.1 | 21.6 | 10.7 | 30.1 | 19.3 | 43.4 | 23.6 | 30.9 | 41.5 | 26.6 | 29.6 | 22.9 | 32.5 | 42.8 | 17.5 | 15.9 | 28.1 | 34.1 | 34.1 | 33.5 | 51.8 | 24.4 | 36 | 32.5 | 29.8 | 23.3 | 20.5 | 25.4 | 26.3 | 12.8 | 34 | 37.1 | 40 | 22.5 | 28.3 | 40.1 | 39.1 | 37.2 | 41.2 | 41 | 26.1 | 36.2 | 46 | 33.6 | 35.4 | 34.2 | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA |
2022 Q1 | 12 months ending with quarter | COVID-19 | Age-adjusted | Deaths per 100,000 | 95 | 75.2 | 119.1 | 121.3 | 133.6 | 123.6 | 113.9 | 62.4 | 89.9 | 50.9 | 54.8 | 78.4 | 106.6 | 116.4 | 43.9 | 78.1 | 118.9 | 82.1 | 112.1 | 109.7 | 146.7 | 108.8 | 46.7 | 66.9 | 70.9 | 115 | 68 | 110.5 | 140.8 | 111.8 | 98.3 | 80.2 | 73.8 | 56.5 | 62.9 | 138.3 | 134.8 | 63.4 | 128.1 | 150.3 | 77.5 | 97.4 | 55.5 | 122.9 | 76.3 | 140.5 | 126.7 | 78.4 | 80.8 | 32.9 | 66.6 | 77.7 | 154 | 145.1 | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA |
2022 Q1 | 12 months ending with quarter | Cancer | Age-adjusted | Deaths per 100,000 | 145.9 | 127.4 | 170.9 | 156 | 159.9 | 167.9 | 134.5 | 131.4 | 125 | 134.1 | 143.8 | 155.4 | 141.3 | 150.4 | 126.7 | 152 | 139.6 | 149.3 | 169 | 152.8 | 179.6 | 161.9 | 136.1 | 139.2 | 161.2 | 159.6 | 143.6 | 162.4 | 184 | 142.9 | 152.4 | 134.2 | 152.2 | 145.3 | 130.3 | 135.6 | 140.8 | 125.3 | 161.5 | 176.7 | 153.7 | 151.8 | 139.1 | 154.3 | 148.6 | 165.2 | 143.5 | 120.6 | 149.8 | 155 | 148.5 | 146.7 | 183.8 | 153.1 | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA |
2022 Q1 | 12 months ending with quarter | Chronic liver disease and cirrhosis | Age-adjusted | Deaths per 100,000 | 14.4 | 10.3 | 18.9 | 25.5 | 16.4 | 17 | 21 | 15.4 | 19.7 | 12.5 | 9.1 | 11.5 | 13.4 | 13.7 | 9.7 | 14.3 | 16.1 | 12.3 | 15.4 | 15.4 | 17.2 | 12.1 | 11.1 | 9.3 | 17.8 | 15.1 | 13.6 | 13.1 | 17.3 | 24.7 | 15 | 17.8 | 15.2 | 14.5 | 8.9 | 41.8 | 17.6 | 8.3 | 14.1 | 19.3 | 18 | 11 | 16.8 | 17.5 | 36.1 | 17.1 | 16.8 | 11.6 | 11.7 | 12.6 | 15.5 | 12.5 | 17.9 | 25 | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA |
2022 Q1 | 12 months ending with quarter | Chronic lower respiratory diseases | Age-adjusted | Deaths per 100,000 | 35.1 | 33.2 | 37.8 | 36.4 | 51.7 | 62.3 | 37 | 26.3 | 38.1 | 23.9 | 17.7 | 36.5 | 32.1 | 41.1 | 17.9 | 40.8 | 44.1 | 32.4 | 52.9 | 43.8 | 58.3 | 39.6 | 26.8 | 24.1 | 43.1 | 39 | 30.1 | 46.7 | 59.9 | 39.6 | 37.3 | 35.4 | 41 | 36 | 21.6 | 38.3 | 41.4 | 22.5 | 43 | 63.5 | 34.1 | 30.8 | 29.4 | 41.6 | 41.6 | 52 | 36.2 | 30.6 | 31.3 | 32.4 | 29.5 | 33.2 | 59.9 | 49.5 | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA |
In this section, the dataset is filtered to retain only records related to firearm-related injuries and their crude mortality rates. The data are then transformed into a long format to align each state with its corresponding firearm death rate. Additionally, states are classified on a five-point Likert scale to indicate the strictness of their gun control laws, ranging from most lax (1) to most strict (5). These preprocessing steps ensure the dataset is clean, consistent, and ready for accurate visualization and analysis.
# Apply the filter to the data
firearm_data <- df %>%
filter(cause_of_death == 'Firearm-related injury' &
year_and_quarter == '2023 Q1' &
time_period == '12 months ending with quarter' &
rate_type == "Age-adjusted")
#Select only the states columns
firearm_df <- firearm_data[1, 9:59]
# Reformat the data
firearm_df <- firearm_df %>%
gather(key = "state", value = "firearm_mortality_rate", starts_with("rate_")) %>%
mutate(firearm_mortality_rate = as.numeric(firearm_mortality_rate),
state = gsub("rate_", "", state)) %>%
filter(state != "district_of_columbia") %>%
arrange(state)
# View first 5 elements of the data
head(firearm_df)
state firearm_mortality_rate
1 alabama 26.4
2 alaska 21.4
3 arizona 19.9
4 arkansas 22.7
5 california 8.6
6 colorado 17.1
Next, we will develop a five-point Likert scale to categorize gun control laws across states, ranging from the loosest to the strictest. Each state will then be assigned to the appropriate category based on data from: https://worldpopulationreview.com/state-rankings/strictest-gun-laws-by-state
# Categories for guns policies per states
likert_values <-c("Very loose", "Very loose","Very loose","Very loose","Very Strict",
"Strict","Very Strict","Strict","Moderate","Very loose",
"Very Strict","Very loose","Very Strict","Loose","Very loose",
"Very loose","Very loose","Very loose","Very loose","Very Strict",
"Very Strict","Moderate","Moderate","Very loose","Very loose","Very loose",
"Moderate","Moderate","Very loose","Very Strict","Moderate","Very Strict",
"Moderate","Very loose","Loose","Very loose","Strict","Strict",
"Strict","Very loose","Very loose","Very loose","Very loose",
"Very loose","Moderate","Strict","Strict","Very loose","Moderate","Very loose")
# Assuming your data frame is named df_ordered
firearm_df$gun_law <- likert_values
# Change the name of the column
firearm_df$state <- c("Alabama", "Alaska", "Arizona", "Arkansas", "California",
"Colorado", "Connecticut", "Delaware", "Florida", "Georgia",
"Hawaii", "Idaho", "Illinois", "Indiana", "Iowa", "Kansas",
"Kentucky", "Louisiana", "Maine", "Maryland", "Massachusetts",
"Michigan", "Minnesota", "Mississippi", "Missouri", "Montana",
"Nebraska", "Nevada", "New Hampshire", "New Jersey", "New Mexico",
"New York", "North Carolina", "North Dakota", "Ohio", "Oklahoma",
"Oregon", "Pennsylvania", "Rhode Island", "South Carolina",
"South Dakota", "Tennessee", "Texas", "Utah", "Vermont", "Virginia",
"Washington", "West Virginia", "Wisconsin", "Wyoming")
# Print the data
head(firearm_df)
state firearm_mortality_rate gun_law
1 Alabama 26.4 Very loose
2 Alaska 21.4 Very loose
3 Arizona 19.9 Very loose
4 Arkansas 22.7 Very loose
5 California 8.6 Very Strict
6 Colorado 17.1 Strict
Correlation between
firearm policy and mortality rate
Correlation between firearm policy and mortality rate Let’s calculate the correlation between strict firearm policy and the mortality rate.
# Calculate correlation coefficient
correlation <- cor(firearm_df$firearm_mortality_rate, as.numeric(factor(firearm_df$gun_law, levels = c("Very loose", "Loose", "Moderate", "Strict", "Very Strict"))))
correlation
[1] -0.6671983
The correlation coefficient of -0.6656803 indicates a strong negative correlation between firearm mortality rates and the stringency of gun control laws. This suggests that as gun control laws become stricter, firearm mortality rates tend to decrease.
Create a heat map
A heatmap is an effective visualization for identifying
patterns and distributions across geographic regions. In this analysis,
the heatmap illustrates the strictness of gun control laws across U.S.
states for the fourth quarter of 2022. Each state is colored according
to its category on a five-point Likert scale, ranging from Most Lax to
Most Strict. This approach allows for easy comparison between states,
highlights regional trends, and visually communicates how firearm
legislation varies across the country. By combining geographic and
categorical data, the heatmap provides an intuitive way to explore the
relationship between gun law strictness and firearm-related
mortality.
# Define a numeric mapping for gun law categories
gun_law_levels <- c("Very loose", "Loose", "Moderate", "Strict", "Very Strict")
# gun_law_colors <- c("#d73027", "#fc8d59", "#fee08b", "#91bfdb", "#4575b4") # red→blue
gun_law_colors <- c("#d73027", "#fc8d59", "#fee08b", "#91bfdb", "#1a9850") # red → green
# Map gun_law to numeric for color scale
firearm_df <- firearm_df %>%
mutate(
state_abbr = state.abb[match(state, state.name)],
state_abbr = ifelse(state == "district_of_columbia", "DC", state_abbr),
gun_law_num = as.numeric(factor(gun_law, levels = gun_law_levels))
)
# Plotly choropleth
fig <- plot_ly(
data = firearm_df,
type = "choropleth",
locations = ~state_abbr,
locationmode = "USA-states",
z = ~gun_law_num, # use numeric mapping
text = ~paste0(
"<b>", tools::toTitleCase(state), "</b><br>",
"Gun Law: ", gun_law, "<br>",
"Firearm Mortality Rate: ", firearm_mortality_rate
),
hoverinfo = "text",
colorscale = list(
list(0.0, gun_law_colors[1]),
list(0.25, gun_law_colors[2]),
list(0.5, gun_law_colors[3]),
list(0.75, gun_law_colors[4]),
list(1.0, gun_law_colors[5])
),
zmin = 1,
zmax = 5,
colorbar = list(
title = "Gun Law Strength",
tickvals = 1:5,
ticktext = c("Most Lax","Lax","Moderate","Strict","Most Strict")
)
) %>%
layout(
title = list(
text = "Gun Laws Strength by US State",
x = 0.5, xanchor = "center", font = list(size = 20)
),
geo = list(
scope = "usa",
projection = list(type = "albers usa"),
showlakes = TRUE,
lakecolor = "rgb(255, 255, 255)"
)
)
fig
The heatmap uncovers distinct geographic patterns in gun law strictness across the United States. States with more lenient firearm regulations tend to cluster in specific regions, whereas states with stricter laws are concentrated elsewhere. By including firearm mortality rates in the hover text, the heatmap provides immediate insights into potential correlations between legislation and death rates. Overall, this visualization emphasizes the role of geographic context in understanding variations in state-level gun control laws and presents a clear visual narrative for policymakers and the public regarding the landscape of firearm regulation in the U.S.
Firearm Mortality Rate
vs. Gun Control Laws
In this analysis, we examine how the strictness of firearm control laws influences firearm mortality rates across U.S. states. By correlating each state’s gun law strictness with its corresponding firearm mortality rate and visualizing the results through a heat map, we uncover a clear pattern: states with stricter firearm regulations tend to experience lower firearm mortality rates.
# Calculate national average
average_rate <- mean(firearm_df$firearm_mortality_rate)
# Reorder gun_law factor
firearm_df$gun_law <- factor(
firearm_df$gun_law,
levels = c("Very loose", "Loose", "Moderate", "Strict", "Very Strict")
)
# Build base ggplot
p <- ggplot(firearm_df, aes(x = gun_law, y = firearm_mortality_rate,
color = firearm_mortality_rate,
text = paste0(
"<b>", state, "</b><br>",
"Gun Law: ", gun_law, "<br>",
"Mortality Rate: ", round(firearm_mortality_rate, 2)
))) +
geom_jitter(size = 5, width = 0.15, alpha = 0.9) +
scale_color_gradient(low = "#2ECC71", high = "#E74C3C", name = "Mortality Rate") +
geom_hline(yintercept = average_rate, linetype = "dashed",
color = "navyblue", size = 1) +
annotate("text", x = 5.1, y = average_rate + 0.3,
label = paste("National Avg:", round(average_rate, 1)),
color = "navyblue", hjust = 0, size = 4.5, fontface = "bold") +
labs(
title = "Firearm Mortality Rate vs Gun Law Strictness (2023 Q1)",
subtitle = "Hover over points to see details for each state",
x = "Gun Law Strictness (Least → Most Restrictive)",
y = "Firearm Mortality Rate per 100,000"
) +
theme_minimal(base_size = 15) +
theme(
plot.title = element_text(size = 20, face = "bold", hjust = 0.5),
plot.subtitle = element_text(size = 14, color = "gray30", hjust = 0.5),
axis.text = element_text(size = 12, color = "gray20"),
axis.title = element_text(size = 14, face = "bold"),
panel.grid.minor = element_blank(),
panel.grid.major.x = element_blank(),
legend.position = "right",
legend.title = element_text(face = "bold")
)
# Convert to interactive hover plot
fig <- ggplotly(p, tooltip = "text")
fig
The national average for firearm mortality stands at 15.5 per 100,000 persons.
The graph indicates that states with strict gun control laws consistently maintain firearm mortality rates below the national average. In contrast, over 70% of states with lenient gun control laws record firearm mortality rates above the national average. Notably, 16 of the 21 states exceeding the national average in firearm mortality have very loose gun control regulations.
The visualizations indicate a trend in which states with more lenient gun laws generally experience higher firearm-related mortality rates, while states with the strictest laws tend to have the lowest rates. Overall, the chart suggests a negative association between gun law strictness and firearm deaths. A minor exception is observed, states with the most stringent laws show slightly higher mortality rates than some states with moderately strict laws, possibly due to unmeasured factors varying across states. In summary, the analysis supports the conclusion that stricter firearm control laws are associated with a reduction in firearm mortality rates across U.S. states.