Here is the R code for mapping and tabulating Toxics Release Inventory data from the U.S. Environmental Protection Agency:
# ============================================================
# TRI Data Analysis and Carcinogen Mapping for Tennessee (2023)
# ============================================================
# ------------------------------------------------------------
# 1. Install and load required packages
# ------------------------------------------------------------
if (!require("tidyverse")) install.packages("tidyverse")
if (!require("leaflet")) install.packages("leaflet")
if (!require("DT")) install.packages("DT")
library(tidyverse)
library(leaflet)
library(DT)
# ------------------------------------------------------------
# 2. Download and load EPA TRI dataset (2023 Tennessee)
# ------------------------------------------------------------
tri <- read.csv(
"https://data.epa.gov/efservice/downloads/tri/mv_tri_basic_download/2023_TN/csv",
as.is = TRUE
)
# ------------------------------------------------------------
# 3. Clean column names for clarity
# ------------------------------------------------------------
names(tri) <- gsub("X\\d+\\.\\.", "", names(tri))
names(tri) <- gsub("[0-9\\d\\.ABCD]+\\.\\.\\.", "", names(tri))
# ------------------------------------------------------------
# 4. Select relevant columns
# ------------------------------------------------------------
tri <- subset(
tri,
select = c(
FACILITY.NAME,
CITY,
LATITUDE,
LONGITUDE,
CHEMICAL,
CARCINOGEN,
FUGITIVE.AIR,
STACK.AIR,
WATER,
UNIT.OF.MEASURE
)
)
options(scipen = 999) # disable scientific notation
# ------------------------------------------------------------
# 5. Convert grams to pounds (where applicable)
# ------------------------------------------------------------
multiplier <- ifelse(tri$UNIT.OF.MEASURE == "Grams", 1 / 453.592, 1)
tri$FUGITIVE.AIR <- multiplier * tri$FUGITIVE.AIR
tri$STACK.AIR <- multiplier * tri$STACK.AIR
tri$WATER <- multiplier * tri$WATER
tri$UNIT.OF.MEASURE <- "Pounds"
# ------------------------------------------------------------
# 6. Handle missing values and compute totals
# ------------------------------------------------------------
tri$FUGITIVE.AIR[is.na(tri$FUGITIVE.AIR)] <- 0
tri$STACK.AIR[is.na(tri$STACK.AIR)] <- 0
tri$WATER[is.na(tri$WATER)] <- 0
tri$TOTAL.POUNDS <- tri$FUGITIVE.AIR + tri$STACK.AIR + tri$WATER
tri$CARCINOGEN.POUNDS <- ifelse(tri$CARCINOGEN == "YES", tri$TOTAL.POUNDS, 0)
# ------------------------------------------------------------
# 7. Filter data to include carcinogenic releases only
# ------------------------------------------------------------
data <- tri %>% filter(CARCINOGEN.POUNDS > 0)
data$LATITUDE <- as.numeric(data$LATITUDE)
data$LONGITUDE <- as.numeric(data$LONGITUDE)
# ------------------------------------------------------------
# 8. Create interactive summary table of carcinogen totals
# ------------------------------------------------------------
summary_table <- data %>%
group_by(CITY, CHEMICAL) %>%
summarize(
Facilities = n_distinct(FACILITY.NAME),
Total_Pounds = round(sum(CARCINOGEN.POUNDS, na.rm = TRUE), 2)
) %>%
arrange(desc(Total_Pounds))
datatable(
summary_table,
options = list(pageLength = 10, scrollX = TRUE),
caption = "Summary of Carcinogenic Chemical Releases by City (2023)"
)
# ------------------------------------------------------------
# 9. Create popup text for interactive map
# ------------------------------------------------------------
data$popup <- paste0(
"<b>Facility name: </b>", data$FACILITY.NAME,
"<br><b>City: </b>", data$CITY,
"<br><b>Carcinogen: </b>", data$CHEMICAL,
"<br><b>Fugitive air: </b>", round(data$FUGITIVE.AIR, 2), " lbs",
"<br><b>Stack air: </b>", round(data$STACK.AIR, 2), " lbs",
"<br><b>Water: </b>", round(data$WATER, 2), " lbs",
"<br><b>Total pounds: </b>", round(data$CARCINOGEN.POUNDS, 2)
)
# ------------------------------------------------------------
# 10. Create interactive map of carcinogenic emissions
# ------------------------------------------------------------
TheMap <- leaflet(data, width = "100%") %>%
addTiles(group = "OSM (default)") %>%
addProviderTiles("Esri.WorldStreetMap", group = "World StreetMap") %>%
addProviderTiles("Esri.WorldImagery", group = "World Imagery") %>%
addMarkers(
lng = ~LONGITUDE,
lat = ~LATITUDE,
popup = ~popup,
clusterOptions = markerClusterOptions()
) %>%
addLayersControl(
baseGroups = c("OSM (default)", "World StreetMap", "World Imagery"),
options = layersControlOptions(collapsed = FALSE)
)
TheMap