Instruction
Introduction
Data
Sources for Critical Mineral Analysis
Data
Cleaning and Preparation
U.S.
Import Dependence Across Low-Carbon Technologies
Key
Statistics for Critical Mineral Supply Sources
Critical
Minerals Overview
Major
U.S. Sources of Critical Minerals
Governance
Scores of Ally Mineral Sources
Governance
Scores of Competitor Mineral Sources
Governance
Scores of Neutral Mineral Sources
Conclusion
Recommendations
The US Geological Survey publishes a list of Strategic Minerals ( https://www.usgs.gov/news/national-news-release/us-geological-survey-releases-2022-list-critical-minerals ). Having a secure supply of these minerals is essential to our security and economic prosperity. However many of these minerals are sourced from outside of the US. This assignment is to develop a reference catalog of the source or sources of each of these minerals and a judgement on the reliability of each source under stressed circumstance (e.g. war, economic crisis, etc.)
Notes:
You will need to identify a source or sources for each of the minerals in the 2022 List of Critical Minerals
You will need to categorize each source country as an ally, a competitor or a neutral party.
You will need to develop data visualizations that tell the story of source dependency and shortfall impact.
Introduction
Strategic minerals form the hidden foundation of modern
life—powering clean-energy technologies, advanced manufacturing,
transportation, and national defense systems. As the United States
accelerates its transition toward renewable energy and digital
infrastructure, the nation’s reliance on a secure and resilient supply
of these minerals has never been more critical. Yet many of the most
essential minerals are sourced almost entirely from abroad, often from
countries with uncertain geopolitical alignment or weak governance.
This analysis examines the U.S. Geological Survey’s 2022 Critical Minerals List and maps each mineral to its major supplier countries. By integrating import-reliance data, geopolitical classifications (Ally, Competitor, Neutral), and global governance indicators, the dashboard highlights where U.S. supply chains are stable—and where they are exposed to strategic risk.
The goal of this story is to provide a clear, evidence-based view of how dependent the United States is on foreign mineral supplies, which countries dominate the market, and how the reliability of these suppliers might shift under stressed conditions such as conflict, economic shocks, or diplomatic disruption. Ultimately, the visualizations illustrate a central challenge: securing the mineral inputs required for economic growth and national security in an increasingly complex global landscape.
This dashboard begins by identifying which technologies rely most heavily on minerals where the United States has very high or complete import dependence—framing the core issue: U.S. clean-energy growth requires minerals the nation does not control.
library(tidyverse)
library(snakecase)
library(RColorBrewer)
library(janitor)
library(cowplot)
library(ggtext) Data Sources for Critical
Mineral Analysis
Critical Minerals List
(criticalminerals.csv): USGS 2022 official list of critical minerals
with classification and usage.
Net Import Reliance (MCS2023 Import Reliance.csv): U.S. dependency (%) on foreign suppliers for each mineral.
MSP Member Countries: U.S.-aligned partner nations securing mineral supply chains.
BRI Countries (BRIcountries.csv): China’s Belt and Road Initiative nations, classified as competitors.
Governance & Economic Indicators (worldgovind.csv, globaleconprosp.csv): Country-level governance metrics and macroeconomic performance of mineral suppliers.
#Critical minerals list
url1 <- "https://raw.githubusercontent.com/BIKASHBHOWMIK15/data-608/main/criticalminerals.csv"
crit_min_df <- read.csv(url1, stringsAsFactors = FALSE)
#Net import reliance
url2 <- "https://raw.githubusercontent.com/BIKASHBHOWMIK15/data-608/main/MCS2023%20Import%20Reliance.csv"
net_imp_rel_df <- read.csv(url2, encoding = "UTF-8", stringsAsFactors = FALSE)
#Minerals Security Partnership (MSP):
#https://www.state.gov/minerals-security-partnership/#:~:text=The%20United%20States%20was%20joined,bolster%20critical%20mineral%20supply%20chains.
msp_sources <- c("Australia", "Canada", "Finland", "France", "Germany",
"Japan", "South Korea", "Sweden", "United Kingdom",
"Europe")
#Belt and Road Initiative (BRI):
#https://greenfdc.org/countries-of-the-belt-and-road-initiative-bri/
url3 <- "https://raw.githubusercontent.com/BIKASHBHOWMIK15/data-608/main/BRIcountries.csv"
bri_countr_df <- read.csv(url3, skip = 3, stringsAsFactors = FALSE)
colnames(bri_countr_df) <- to_screaming_snake_case(colnames(bri_countr_df))
url4 <- "https://raw.githubusercontent.com/BIKASHBHOWMIK15/data-608/main/worldgovind.csv"
world_gov_df <- read.csv(url4, stringsAsFactors = FALSE)
colnames(world_gov_df) <- to_screaming_snake_case(colnames(world_gov_df))
url5 <- "https://raw.githubusercontent.com/BIKASHBHOWMIK15/data-608/main/globaleconprosp.csv"
global_econ_prosp_df <- read.csv(url5, stringsAsFactors = FALSE)
colnames(global_econ_prosp_df) <- to_screaming_snake_case(colnames(global_econ_prosp_df)) Data Cleaning and
Preparation
Standardization: Simplified
commodity names and harmonized country names.
Merging: Combined critical minerals with net import reliance data and ranked by import share.
Source Splitting: Separated major import sources into individual columns.
Data Cleaning: Handled missing values, converted textual thresholds to numeric, and categorized import dependence.
Filtering: Removed irrelevant processed materials to focus on primary critical minerals.
rare_earths <- c("YTTERBIUM", "THULIUM", "TERBIUM", "SAMARIUM",
"PRASEODYMIUM", "NEODYMIUM", "LUTETIUM", "LANTHANUM",
"HOLMIUM", "GADOLINIUM", "EUROPIUM", "ERBIUM",
"DYSPROSIUM", "CERIUM")
plat_grp_metals <- c("IRIDIUM", "RHODIUM", "RUTHENIUM")
patt <- c("ARSENIC,\\sall\\sforms", "GRAPHITE\\s\\(NATURAL\\)",
"NIOBIUM\\s\\(COLUMBIUM\\)", "TITANIUM,\\ssponge",
"ANTIMONY,\\smetal\\sand\\soxide",
"TITANIUM\\sMINERAL\\sCONCENTRATES", "CHROMIUM,\\sall\\sforms ",
"TIN,\\srefined", "ZINC,\\srefined", "ALUMINUM", "BAUXITE",
"ALUMINA", "MAGNESIUM\\sMETAL", "MAGNESIUM\\sCOMPOUNDS",
"ZIRCONIUM,\\sores\\sand\\sconcentrates",
"RARE\\sEARTHS,\\scompounds\\sand\\smetals,\\sincluding\\slanthanides")
repl <- c("ARSENIC", "GRAPHITE", "NIOBIUM", "TITANIUM (SPONGE)",
"ANTIMONY", "TITANIUM (MINERAL CONCENTRATES)", "CHROMIUM",
"TIN", "ZINC", "ALUMINUM (METAL)", "ALUMINUM (BAUXITE)",
"ALUMINUM (ALUMINA)", "MAGNESIUM (METAL)", "MAGNESIUM (COMPOUNDS)",
"ZIRCONIUM", "RARE EARTHS*")
names(repl) <- patt
patt2 <- c("Republic of Korea", "United Arab Emirates")
repl2 <- c("South Korea", "UAE")
names(repl2) <- patt2
net_imp_rel_df <- net_imp_rel_df |>
mutate(Commodity = str_replace_all(Commodity, pattern = repl),
Major_Import_Sources_2018_2021 = str_replace_all(
Major_Import_Sources_2018_2021, pattern = repl2))
drop <- c("Crit_Min", "crit_min", "Source", "Major_Import_Sources_2018_2021")
new_cols <- c("Maj_Source_1", "Maj_Source_2", "Maj_Source_3", "Maj_Source_4")
main_df <- crit_min_df |>
left_join(net_imp_rel_df, by = join_by(IMPORTED_AS == Commodity),
relationship = "many-to-one") |>
arrange(Import_Share_Rank, IMPORTED_AS, CRIT_MIN) |>
mutate(Maj_Sources = trimws(Major_Import_Sources_2018_2021)) |>
select(-all_of(drop)) |>
separate_wider_delim(Maj_Sources,
delim = ", ", names = new_cols,
too_few = "align_start", cols_remove = FALSE)
colnames(main_df) <- to_screaming_snake_case(colnames(main_df))
# Missing info filled in:
missing <- c("BERYLLIUM", "HAFNIUM")
beryllium_row <- c("BERYLLIUM", "BERYLLIUM", NA, "<20", "Kazakhstan", "Japan", "Latvia",
"Brazil", "Kazakhstan, Japan, Latvia, Brazil")
hafnium_row <- c("HAFNIUM", "HAFNIUM", NA, NA, "Germany", "France", "China", "Russia",
"Germany, France, China, Russia")
missing_rows <- as.data.frame(rbind(beryllium_row, hafnium_row))
rownames(missing_rows) <- NULL
colnames(missing_rows) <- colnames(main_df)
missing_rows$IMPORT_SHARE_RANK <- as.numeric(missing_rows$IMPORT_SHARE_RANK)
main_df <- main_df |>
filter(!CRIT_MIN %in% missing) |>
bind_rows(missing_rows)
main_df$NET_IMP_REL_PCT <- main_df$NET_IMPORT_RELIANCE_PCT_2022
main_df$NET_IMP_REL_PCT <- gsub(">95", "96", main_df$NET_IMP_REL_PCT)
main_df$NET_IMP_REL_PCT <- gsub(">75", "76", main_df$NET_IMP_REL_PCT)
main_df$NET_IMP_REL_PCT <- gsub(">50", "51", main_df$NET_IMP_REL_PCT)
main_df$NET_IMP_REL_PCT <- gsub("<50", "49", main_df$NET_IMP_REL_PCT)
main_df$NET_IMP_REL_PCT <- gsub(">25", "26", main_df$NET_IMP_REL_PCT)
main_df$NET_IMP_REL_PCT <- gsub("<20", "19", main_df$NET_IMP_REL_PCT)
filt <- c("ALUMINUM (ALUMINA)", "ALUMINUM (BAUXITE)", "MAGNESIUM (COMPOUNDS)",
"TITANIUM (MINERAL CONCENTRATES)")
main_df <- main_df |>
select(-NET_IMPORT_RELIANCE_PCT_2022) |>
mutate(NET_IMP_REL_PCT = as.numeric(NET_IMP_REL_PCT),
DEPENDENCE = factor(case_when(is.na(NET_IMP_REL_PCT) ~ NA,
NET_IMP_REL_PCT < 25 ~ "Low Dependence",
NET_IMP_REL_PCT < 50 ~ "Medium Dependence",
NET_IMP_REL_PCT < 75 ~ "High Dependence",
NET_IMP_REL_PCT < 100 ~ "Very High Dependence",
TRUE ~ "Complete Dependence"),
levels = c("Low Dependence",
"Medium Dependence",
"High Dependence",
"Very High Dependence",
"Complete Dependence"),
exclude = NULL)) |>
arrange(IMPORT_SHARE_RANK, IMPORTED_AS, CRIT_MIN) |>
filter(!IMPORTED_AS %in% filt)sources <- c(unique(c(main_df$MAJ_SOURCE_1, main_df$MAJ_SOURCE_2,
main_df$MAJ_SOURCE_3, main_df$MAJ_SOURCE_4)))
sources <- as.data.frame(sources[!is.na(sources)])
colnames(sources) <- "Source"
sources <- sources |>
arrange(Source)
patt <- c("Russian Federation", "Korea, Rep.", "United Arab Emirates")
repl <- c("Russia", "South Korea", "UAE")
names(repl) <- patt
bri_countr_df <- bri_countr_df |>
mutate(COUNTRY = str_replace_all(COUNTRY, pattern = repl))
bri_sources <- c(bri_countr_df$COUNTRY, "China")
sources <- sources |>
mutate(Category = case_when(Source %in% msp_sources ~ "Ally",
# note that if a country is in both, the Ally label is
# preferred; this applies to South Korea
Source %in% bri_sources ~ "Competitor",
TRUE ~ "Neutral"))This code maps low-carbon technologies to the critical minerals they require, creating a binary usage matrix. It reshapes the data, calculates totals, and filters out technologies with no mineral use. Finally, it joins with import-dependence data to show U.S. reliance on each critical mineral.
low_carbon_tech <- matrix(c(1, 1, 0, 0, 0, 1, 1, 1, 1, 0,
1, 0, 0, 1, 1, 1, 1, 1, 1, 1,
0, 0, 0, 0, 0, 1, 0, 1, 1, 1,
0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
0, 1, 0, 0, 0, 0, 1, 0, 0, 0,
0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
1, 0, 0, 1, 1, 1, 0, 1, 1, 1,
1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 0, 1, 1, 1, 1, 1, 1, 1,
0, 0, 0, 1, 1, 0, 1, 1, 1, 0,
0, 0, 0, 0, 0, 1, 1, 1, 0, 0,
1, 1, 0, 1, 0, 1, 1, 0, 0, 0),
nrow = 12, ncol = 10, byrow = TRUE)
rownames(low_carbon_tech) <- c("Aluminum", "Chromium", "Cobalt", "Graphite",
"Indium", "Lithium", "Manganese", "Neodymium",
"Nickel", "Titanium", "Vanadium", "Zinc")
colnames(low_carbon_tech) <- c("Wind", "Solar Photovoltaic", "Concentrated Solar Power",
"Hydro", "Geothermal", "Energy Storage", "Nuclear",
"Coal", "Gas", "Carbon Capture and Storage")
low_carbon_tech <- as.data.frame(t(low_carbon_tech))
low_carbon_tech <- low_carbon_tech[, order(colSums(-low_carbon_tech))]
low_carbon_tech$ROW_TOTAL <- rowSums(low_carbon_tech)
low_carbon_tech <- low_carbon_tech |>
filter(ROW_TOTAL > 0) |>
rownames_to_column(var = "LOW_CARBON_TECHNOLOGY") |>
arrange(desc(ROW_TOTAL))
skip <- c("LOW_CARBON_TECHNOLOGY", "ROW_TOTAL")
sel <- c("CRIT_MIN", "DEPENDENCE")
low_carbon_tech_piv <- low_carbon_tech |>
pivot_longer(cols = -all_of(skip), names_to = "x", values_to = "val") |>
group_by(x) |>
mutate(COL_TOTAL = sum(val)) |>
ungroup() |>
mutate(X = str_to_upper(x)) |>
left_join(main_df |> select(all_of(sel)),
by = join_by(X == CRIT_MIN),
relationship = "many-to-many",
multiple = "first")|>
select(-X) U.S. Import Dependence
Across Low-Carbon Technologies
This chart shows which low-carbon technologies rely on minerals that the U.S. must heavily import. Only minerals with very high or complete import dependence are highlighted. Each tile represents whether a mineral is required for a specific technology. Technologies like EV batteries and wind turbines depend on several high-risk minerals. This dependence creates potential supply-chain vulnerabilities for the clean-energy transition.
drop <- c("CRIT_MIN")
piv <- c("MAJ_SOURCE_1", "MAJ_SOURCE_2", "MAJ_SOURCE_3", "MAJ_SOURCE_4")
sources_imported_as_piv <- main_df |>
select(-all_of(drop)) |>
distinct(IMPORTED_AS, .keep_all = TRUE) |>
pivot_longer(cols = all_of(piv), names_to = "src_rank", values_to = "src") |>
mutate(src_rank = as.numeric(str_replace_all(src_rank, "MAJ_SOURCE_", ""))) |>
left_join(sources, by = join_by(src == Source),
relationship = "many-to-one") |>
group_by(src) |>
mutate(src_count = n())
drop <- c("IMPORTED_AS")
sources_crit_min_piv <- main_df |>
select(-all_of(drop)) |>
distinct(CRIT_MIN, .keep_all = TRUE) |>
pivot_longer(cols = all_of(piv), names_to = "src_rank", values_to = "src") |>
mutate(src_rank = as.numeric(str_replace_all(src_rank, "MAJ_SOURCE_", ""))) |>
left_join(sources, by = join_by(src == Source),
relationship = "many-to-one") |>
group_by(src) |>
mutate(src_count = n())drop <- c("IMPORTED_AS")
key_stats_df <- main_df |>
select(-all_of(drop)) |>
distinct(CRIT_MIN, .keep_all = TRUE) |>
mutate(DEPENDENCE = case_when(DEPENDENCE == "Very High Dependence" ~ "Very High or Complete Dependence",
DEPENDENCE == "Complete Dependence" ~ "Very High or Complete Dependence",
TRUE ~ DEPENDENCE)) |>
group_by(DEPENDENCE) |>
summarize(dep_count = n()) |>
mutate(dep_total = sum(dep_count),
dep_percent = round(dep_count / dep_total * 100, 2)) |>
filter(DEPENDENCE == "Very High or Complete Dependence")
cols <- c("Stat", "count", "total", "percent")
colnames(key_stats_df) <- cols
key_stats_df[] <- lapply(key_stats_df, as.character)
has_ally_source_df <- sources_crit_min_piv |>
filter(Category == "Ally")
has_ally_source_crit_min_vec <- unique(has_ally_source_df$CRIT_MIN)
a <- c("Has Ally Source", "41", "50", as.character(round(41 / 50 * 100, 2)))
b <- c("Has No Ally Source", "6", "50", as.character(round(6 / 50 * 100, 2)))
new_rows <- as.data.frame(rbind(a, b))
rownames(new_rows) <- NULL
colnames(new_rows) <- cols
src1_df <- sources_crit_min_piv |>
filter(src_rank == 1) |>
group_by(src) |>
summarize(src1_count = n()) |>
mutate(src1_total = sum(src1_count),
src1_percent = round(src1_count / src1_total * 100, 2))
src1_df_can_china_only <- src1_df |>
filter(src == "Canada" | src == "China") |>
mutate(src = ifelse(src == "Canada", "Canada Top Supplier",
"China Top Supplier"))
colnames(src1_df_can_china_only) <- cols
src1_df_can_china_only[] <- lapply(src1_df_can_china_only, as.character)
key_stats_df <- key_stats_df |>
bind_rows(new_rows, src1_df_can_china_only)
sel <- c("CRIT_MIN", "IMPORTED_AS")
has_ally_source_df <- has_ally_source_df |>
left_join(main_df |> select(sel), relationship = "many-to-one")has_ally_source_imp_as_vec <- unique(has_ally_source_df$IMPORTED_AS)
sources_imported_as_piv <- sources_imported_as_piv |>
mutate(Has_Ally_Src = ifelse(IMPORTED_AS %in% has_ally_source_imp_as_vec,
"Yes", "No"))
palette <- brewer.pal(n = 12, name = "Paired")
fil <- c(palette[2], palette[8], greys[6])
facevec <- rev(c("bold", rep("plain", 11)))
colvec <- rev(c(palette[6], rep("black", 11)))
title_md <- "The US completely depends on imports for 12 critical minerals and <span style='color:#E31A1C;'>has no
ally sources</span> among its top four suppliers of arsenic"
cap_str <- "Throughout, 'Ally' includes members of the Minerals Security Partnership, while 'Competitor' includes China and\nthe members of its Belt and Road Initiative. (South Korea is the only source that is a member of both, and it is\nclassified here as 'Ally.') All other sources are labeled 'Neutral.'"
library(ggrepel)
p2a <- sources_imported_as_piv |>
filter(!is.na(src) & DEPENDENCE == "Complete Dependence") |>
ggplot(aes(x = src_rank, y = reorder(IMPORTED_AS, desc(IMPORTED_AS)))) +
geom_tile(aes(fill = Category), col = "white") +
geom_text(aes(label = src), col = "white") +
scale_fill_manual(values = fil) +
labs(title = title_md,
caption = cap_str,
fill = "") +
facet_wrap(~ DEPENDENCE, scales = "free_y", ncol = 1) +
theme(legend.position = "right",
plot.title = element_markdown(),
plot.title.position = "plot",
plot.caption.position = "plot",
plot.caption = element_text(hjust = 0),
axis.title = element_blank(),
axis.line = element_blank(),
axis.ticks = element_blank(),
axis.text.y = element_text(face = facevec, color = colvec))facevec <- rev(c("bold", "bold", "plain", "bold", rep("plain", 3),
"bold", "plain", "plain"))
colvec <- rev(c(palette[6], palette[6], "black", palette[6], rep("black", 3),
palette[6], "black", "black"))
title_md <- "The US depends very highly (75%+) on imports for 23 critical minerals and <span style='color:#E31A1C;'>has no
ally sources</span> among its top four suppliers of antimony, barite, chromium, or tin"
cap_str <- "RARE EARTHS* includes aggregated import data for 14 critical minerals."
library(ggrepel)
p2b <- sources_imported_as_piv |>
filter(!is.na(src) & DEPENDENCE == "High Dependence") |>
ggplot(aes(x = src_rank, y = reorder(IMPORTED_AS, desc(IMPORTED_AS)))) +
geom_tile(aes(fill = Category), color = "white") +
geom_text_repel(aes(label = src),
color = "white",
size = 3,
box.padding = 0.3,
point.padding = 0.2,
max.overlaps = Inf) +
scale_fill_manual(values = fil) +
labs(title = title_md,
caption = cap_str,
fill = "") +
facet_wrap(~ DEPENDENCE, scales = "free_y", ncol = 1) +
theme(legend.position = "right",
plot.title = element_markdown(),
plot.title.position = "plot",
plot.caption.position = "plot",
plot.caption = element_text(hjust = 0),
axis.title = element_blank(),
axis.line = element_blank(),
axis.ticks = element_blank(),
axis.text.y = element_text(face = facevec, color = colvec))title_md <- "The US is highly dependent (50%+) on imports for seven critical minerals,
none of which are exclusively available from competitors or neutral parties"
p2c <- sources_imported_as_piv |>
filter(!is.na(src) & DEPENDENCE == "High Dependence") |>
ggplot(aes(x = src_rank, y = reorder(IMPORTED_AS, desc(IMPORTED_AS)))) +
geom_tile(aes(fill = Category), col = "white") +
geom_text(aes(label = src), col = "white") +
scale_fill_manual(values = fil) +
labs(title = title_md,
fill = "") +
facet_wrap(~ DEPENDENCE, scales = "free_y", ncol = 1) +
theme(legend.position = "right",
plot.title = element_markdown(),
plot.title.position = "plot",
axis.title = element_blank(),
axis.line = element_blank(),
axis.ticks = element_blank())
levs <- c("Medium Dependence", "Low Dependence")
facevec <- rev(c("bold", rep("plain", 2)))
colvec <- rev(c(palette[6], rep("black", 2)))
title_md <- "The US is low (<25%) to medium (<50%) dependent on imports for four
critical minerals and <span style='color:#E31A1C;'>has no ally sources</span> among its top four suppliers of lithium"
p2d <- sources_imported_as_piv |>
filter(!is.na(src) & DEPENDENCE %in% levs) |>
ggplot(aes(x = src_rank, y = reorder(IMPORTED_AS, desc(IMPORTED_AS)))) +
geom_tile(aes(fill = Category), col = "white") +
geom_text(aes(label = src), col = "white") +
scale_fill_manual(values = fil) +
labs(title = title_md,
fill = "") +
facet_wrap(~ factor(DEPENDENCE, levels = levs), scales = "free_y", ncol = 1) +
theme(legend.position = "right",
plot.title = element_markdown(),
plot.title.position = "plot",
axis.title = element_blank(),
axis.line = element_blank(),
axis.ticks = element_blank(),
axis.text.y = element_text(face = facevec, color = colvec))This code displays the prepared pivoted dataset p2a, showing the relationship between imported commodities, critical minerals, and their major import sources.
This code displays the p2b dataset, which provides a pivoted view of critical minerals with their corresponding major import sources, including source counts for analysis.
This code displays the p2c dataset, showing the U.S. import dependence on critical minerals by source, highlighting high-dependence commodities for visualization and analysis.
U.S. Import Dependence on High- and Medium-Risk Critical Minerals
The charts show how dependent the U.S. is on foreign suppliers for key critical minerals. Seven minerals fall under high import dependence, but none rely solely on competitors or neutral countries. Four minerals show low to medium dependence, yet lithium stands out with no ally sources among top suppliers. Each tile represents one of the top four supplier countries and their classification (Ally, Neutral, Competitor). These patterns highlight where U.S. supply chains are relatively secure—and where strategic vulnerabilities remain.
Key Statistics for
Critical Mineral Supply Sources
This chunk processes World Bank governance indicators, categorizes
countries by percentile rank,
and prepares the key_stats_df dataset for plotting US critical mineral
dependencies.
keep <- c("Control of Corruption: Percentile Rank",
"Government Effectiveness: Percentile Rank",
"Political Stability and Absence of Violence/Terrorism: Percentile Rank",
"Regulatory Quality: Percentile Rank")
shorten <- c("Corruption Control", "Government Effectiveness", "Political Stability",
"Regulatory Quality")
names(shorten) <- keep
sel <- c("COUNTRY_NAME", "SERIES_NAME", "X_2022_YR_2022")
patt <- c("Russian Federation", "Korea, Rep.", "United Arab Emirates")
repl <- c("Russia", "South Korea", "UAE")
names(repl) <- patt
world_gov_df <- world_gov_df |>
filter(SERIES_NAME %in% keep) |>
select(all_of(sel)) |>
mutate(SERIES_NAME = str_replace_all(SERIES_NAME, pattern = shorten),
COUNTRY_NAME = str_replace_all(COUNTRY_NAME, pattern = repl))
sources <- sources |>
left_join(world_gov_df, by = join_by(Source == COUNTRY_NAME),
relationship = "one-to-many")
colnames(sources) <- c("Source", "Category", "World_Gov_Ind", "Percentile_Rank")
sources$Percentile_Rank <- round(as.numeric(sources$Percentile_Rank), 2)
sources <- sources |>
mutate(Percentile_Rank_Cat = factor(case_when(is.na(Percentile_Rank) ~ NA,
Percentile_Rank < 20 ~ "Very Poor",
Percentile_Rank < 40 ~ "Poor",
Percentile_Rank < 60 ~ "Okay",
Percentile_Rank < 80 ~ "Good",
TRUE ~ "Very Good"),
levels = c("Very Poor", "Poor", "Okay",
"Good", "Very Good"),
exclude = NULL))
total_sources <- length(unique(sources$Source))
scores <- c("Poor", "Very Poor")
poor_very_poor_df <- sources |>
filter(Percentile_Rank_Cat %in% scores)
poor_very_poor_vec <- unique(poor_very_poor_df$Source)
a <- c("Has Poor/Very Poor WGIs", "19", "38", as.character(round(19 / 38 * 100, 2)))
b <- c("Does Not Have Poor/Very Poor WGIs", "19", "38",
as.character(round(19 / 38 * 100, 2)))
new_rows <- as.data.frame(rbind(a, b))
rownames(new_rows) <- NULL
colnames(new_rows) <- cols
rem <- c("Has Ally Source", "Canada Top Supplier", "Does Not Have Poor/Very Poor WGIs")
key_stats_df <- key_stats_df |>
bind_rows(new_rows) |>
filter(!Stat %in% rem)
key_stats_df$x <- c(0.3, 0.7, 0.1, 0.6)
key_stats_df$y <- c(0.8, 0.65, 0.4, 0.25)
key_stats_df$Quad <- c(1, 2, 3, 4)
key_stats_df <- key_stats_df |>
mutate(Label = paste0(percent, "%"))
key_stats_df$Annotation1 <- c("The US is very highly (76%+)\nor completely (100%) dependent on imports for", "The US has no allies\namong the top four suppliers of", "China is the US's\nnumber one supplier of", NA)
key_stats_df$Annotation2 <- c("of critical minerals", "of critical minerals", "of critical minerals",
"of the US's critical mineral sources are countries\nwith Poor or Very Poor World Governance Indicators")This plot shows key statistics for the critical minerals identified by the US Geological Survey, highlighting their classification across four quadrants.
Major U.S. Sources of
Critical Minerals
This plot highlights that only three countries other than China are
the top U.S. sources for more than one critical mineral.
China dominates the number-one positions compared to other
countries.
palette <- brewer.pal(n = 12, name = "Paired")
fil <- palette[9:10]
col <- palette[9:10]
title_str = "Only three countries other than China are number one US sources of more\nthan one critical mineral, and their numbers are dwarfed in comparison"
p3 <- src1_df |>
filter(!is.na(src) & src1_count > 1) |>
mutate(highlight = as.factor(ifelse(src == "China", 1, 0))) |>
ggplot(aes(x = reorder(src, desc(src1_count)))) +
geom_col(aes(fill = highlight, y = src1_count, color = highlight)) +
geom_text(aes(label = src1_count, y = src1_count, color = highlight),
vjust = -0.75, size = 4, fontface = "bold") +
geom_text(aes(label = src), y = 0, color = "white",
vjust = -0.75, size = 4, fontface = "bold") +
scale_y_continuous(limits = c(0, 27), breaks = seq(0, 24, 3)) +
scale_fill_manual(values = fil) +
scale_color_manual(values = col) +
labs(y = "",
x = "",
title = title_str) +
theme(legend.position = "none",
plot.title.position = "plot",
axis.line = element_blank(),
axis.ticks = element_blank(),
axis.text.x = element_blank(),
panel.grid.major.y = element_line(color = greys[3], size = 0.25,
linetype = 1))
## Warning: The `size` argument of `element_line()` is deprecated as of ggplot2 3.4.0.
## ℹ Please use the `linewidth` argument instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
p3 Governance Scores of Ally
Mineral Sources
This plot shows that ally sources of critical minerals generally
score well on the World Bank’s governance indicators.
It visualizes the stacked percentile categories for each governance
indicator.
sources_sum <- sources |>
filter(Source != "Europe") |>
group_by(Category, World_Gov_Ind, Percentile_Rank_Cat) |>
summarize(n = n()) |>
group_by(Category, World_Gov_Ind) |>
mutate(tot = sum(n),
perc = round(n / tot * 100, 1),
lab = ifelse(perc > 5, paste0(format(perc, nsmall = 0), "%"), NA),
col = ifelse(Percentile_Rank_Cat == "Okay", "black", "white"))
## `summarise()` has grouped output by 'Category', 'World_Gov_Ind'. You can
## override using the `.groups` argument.
palette <- brewer.pal(n = 11, name = "RdYlBu")
fil <- palette[c(6, 8, 10)]
col <- c("black", "white")
allies <- unique(sources |> filter(Category == "Ally") |> select(Source))
allies <- paste(as.character(unlist(allies)), collapse = ", ")
competitors <- unique(sources |> filter(Category == "Competitor") |> select(Source))
competitors <- as.character(unlist(competitors))
competitors1 <- paste(competitors[1:11], collapse = ", ")
competitors2 <- paste(competitors[12:22], collapse = ", ")
neutrals <- unique(sources |> filter(Category == "Neutral") |> select(Source))
neutrals <- paste(as.character(unlist(neutrals)), collapse = ", ")
title_str = "Ally sources of critical minerals score relatively well on the World Bank's\ngovernance indicators"
cap_str = paste0("Ally sources include: ", allies)
p4a <- sources_sum |>
filter(Category == "Ally") |>
ggplot(aes(x = World_Gov_Ind, y = perc, group = Percentile_Rank_Cat,
color = Percentile_Rank_Cat, fill = Percentile_Rank_Cat)) +
geom_col(position = "stack", lwd = 1.5, color = "white") +
geom_text(aes(label = lab, color = col), position = position_stack(vjust = 0.5),
size = 3, fontface = "bold") +
scale_fill_manual(values = fil, guide = guide_legend(reverse = TRUE)) +
scale_color_manual(values = col, guide = "none") +
scale_y_continuous(limits = c(0, 100), breaks = seq(0, 100, 10)) +
facet_grid(World_Gov_Ind ~ Category, scales = "free_y") +
theme(legend.position = "top",
legend.title = element_blank(),
plot.title.position = "plot",
plot.caption.position = "plot",
plot.caption = element_text(hjust = 0),
axis.line = element_blank(),
axis.text.x = element_blank(),
strip.text.y.right = element_blank(),
axis.ticks = element_blank()) +
labs(x = "",
y = "",
title = title_str,
caption = cap_str) +
coord_flip()
p4a Governance Scores of
Competitor Mineral Sources
This plot highlights how many competitor sources of critical minerals
score relatively poorly on the World Bank’s governance indicators.
It shows the stacked percentile categories for each governance
indicator.
title_str = "In contrast, many competitor sources of critical minerals score relatively poorly on the\nWorld Bank's governance indicators"
cap_str = paste0("Competitor sources include: ", competitors1, ",\n", competitors2)
fil <- palette[c(2, 4, 6, 8, 10)]
p4b <- sources_sum |>
filter(Category == "Competitor") |>
ggplot(aes(x = World_Gov_Ind, y = perc, group = Percentile_Rank_Cat,
color = Percentile_Rank_Cat, fill = Percentile_Rank_Cat)) +
geom_col(position = "stack", lwd = 1.5, color = "white") +
geom_text(aes(label = lab, color = col), position = position_stack(vjust = 0.5),
size = 3, fontface = "bold") +
scale_fill_manual(values = fil, guide = guide_legend(reverse = TRUE)) +
scale_color_manual(values = col, guide = "none") +
scale_y_continuous(limits = c(0, 100), breaks = seq(0, 100, 10)) +
facet_grid(World_Gov_Ind ~ Category, scales = "free_y") +
theme(legend.position = "top",
legend.title = element_blank(),
plot.title.position = "plot",
plot.caption.position = "plot",
plot.caption = element_text(hjust = 0),
axis.line = element_blank(),
axis.text.x = element_blank(),
strip.text.y.right = element_blank(),
axis.ticks = element_blank()) +
labs(x = "",
y = "",
title = title_str,
caption = cap_str) +
coord_flip()
p4b Governance Scores of
Neutral Mineral Sources
This plot shows the distribution of governance indicator scores for
neutral mineral sources.
It highlights the proportion of each percentile category within these
sources.
title_str = "While neutral sources have more mixed scores on the World Bank's\ngovernance indicators"
cap_str = paste0("Neutral sources include: ", neutrals)
p4c <- sources_sum |>
filter(Category == "Neutral") |>
ggplot(aes(x = World_Gov_Ind, y = perc, group = Percentile_Rank_Cat,
color = Percentile_Rank_Cat, fill = Percentile_Rank_Cat)) +
geom_col(position = "stack", lwd = 1.5, color = "white") +
geom_text(aes(label = lab, color = col), position = position_stack(vjust = 0.5),
size = 3, fontface = "bold") +
scale_fill_manual(values = fil, guide = guide_legend(reverse = TRUE)) +
scale_color_manual(values = col, guide = "none") +
scale_y_continuous(limits = c(0, 100), breaks = seq(0, 100, 10)) +
facet_grid(World_Gov_Ind ~ Category, scales = "free_y") +
theme(legend.position = "top",
legend.title = element_blank(),
plot.title.position = "plot",
plot.caption.position = "plot",
plot.caption = element_text(hjust = 0),
axis.line = element_blank(),
axis.text.x = element_blank(),
strip.text.y.right = element_blank(),
axis.ticks = element_blank()) +
labs(x = "",
y = "",
title = title_str,
caption = cap_str) +
coord_flip()
p4cIn conclusion, the analysis of mineral demand and import data provides valuable insights into the strategic importance of critical minerals for the United States. Key findings:
Importance of Critical Minerals: The US Geological Survey identifies certain minerals as critical due to their essential role in national security and economic prosperity. These minerals are crucial for various industries, including clean energy technologies like solar PV, wind power, electric vehicles, and grid battery storage.
Dependency on Foreign Sources: Despite their importance, many critical minerals are sourced from outside the US. This dependency raises concerns about supply chain vulnerabilities, especially during times of geopolitical tension, economic crises, or trade disruptions.
Categorization of Source Countries: As part of the assignment, each source country for critical minerals needs to be categorized as an ally, competitor, or neutral party. Understanding the geopolitical dynamics of mineral sourcing is essential for assessing reliability under stressed circumstances.
1. Strengthen Supply Chain Diversification The analysis shows that several critical minerals come predominantly from countries with weak governance scores. The U.S. should broaden import sources by engaging with countries that have stronger institutional performance and proven regulatory stability.
2. Increase Domestic Production Where Feasible For minerals where domestic resources exist, policy incentives such as streamlined permitting, support for exploration, or public–private partnerships can help reduce long-term reliance on higher-risk suppliers.
3. Invest in Recycling and Circular Material Systems Expanding recycling and developing new technologies for mineral recovery reduces primary demand and lowers exposure to geopolitical risk.
4. Build Strategic Alliances with Trusted Partners Collaboration with allies—through trade agreements, shared investments, or joint research—can ensure more stable and transparent supply chains for high-risk minerals.
5. Monitor Governance and Risk Indicators Continuously Governance conditions change over time. A monitoring framework using World Bank indicators, political risk scores, and trade dependency trends should be integrated into long-term procurement planning.
6. Support R&D for Substitutes and Efficiency Improvements Investing in alternative materials and improving efficiency in mineral-intensive technologies (battery chemistries, magnets, semiconductors) can reduce exposure to vulnerable points in the supply chain.