Objective

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:

Packages

library(tidyverse)
library(snakecase)
library(RColorBrewer)
library(janitor)
library(cowplot)
library(ggtext)

Theme

cur_theme <- theme_set(theme_classic())
greys <- brewer.pal(n = 9, name = "Greys")

Data

#Critical minerals list
url1 <- "https://raw.githubusercontent.com/Meccamarshall/Data608/main/Story7/criticalminerals.csv"
crit_min_df <- read.csv(url1)

#Net import reliance
url2 <- "https://raw.githubusercontent.com/Meccamarshall/Data608/main/Story7/MCS2023%20Import%20Reliance.csv"
net_imp_rel_df <- read.csv(url2, encoding = "UTF-8")

#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/Meccamarshall/Data608/main/Story7/BRIcountries.csv"
bri_countr_df <- read.csv(url3, skip = 3)
colnames(bri_countr_df) <- to_screaming_snake_case(colnames(bri_countr_df))

url4 <- "https://raw.githubusercontent.com/Meccamarshall/Data608/main/Story7/worldgovind.csv"
world_gov_df <- read.csv(url4)
colnames(world_gov_df) <- to_screaming_snake_case(colnames(world_gov_df))

url5 <- "https://raw.githubusercontent.com/Meccamarshall/Data608/main/Story7/globaleconprosp.csv"
global_econ_prosp_df <- read.csv(url5)
colnames(global_econ_prosp_df) <- to_screaming_snake_case(colnames(global_econ_prosp_df))
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"))
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)
palette <- brewer.pal(n = 12, name = "Paired")
fil <- palette[3:4]
title_str <- "Low-Carbon Technologies Rely on Critical Minerals the US Is Very Highly or\nCompletely Dependent on Importing, Endangering a Clean Energy Transition"
cap_str <- "https://www.worldbank.org/en/topic/extractiveindustries/brief/climate-smart-mining-minerals-for-climate-action"
incl <- c("Very High Dependence", "Complete Dependence")
p1 <- low_carbon_tech_piv |>
    filter(val == 1 & DEPENDENCE %in% incl) |>
    ggplot() +
    geom_tile(aes(x = reorder(x, COL_TOTAL, decreasing = TRUE),
                  y = reorder(LOW_CARBON_TECHNOLOGY, ROW_TOTAL),
                  fill = DEPENDENCE),
                  col = "white") +
    scale_fill_manual(values = fil) +
    facet_wrap(~LOW_CARBON_TECHNOLOGY, scales = "free_y", ncol = 3, dir = "v") +
    labs(fill = "",
         title = title_str,
         caption = cap_str) +
    theme(legend.position = "bottom",
          plot.title.position = "plot",
          plot.caption.position = "plot",
          plot.caption = element_text(hjust = 0),
          axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1),
          axis.title = element_blank(),
          axis.line = element_blank(),
          axis.ticks = element_blank(),
          axis.text.y = element_blank())
p1

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")
## Warning: Using an external vector in selections was deprecated in tidyselect 1.1.0.
## ℹ Please use `all_of()` or `any_of()` instead.
##   # Was:
##   data %>% select(sel)
## 
##   # Now:
##   data %>% select(all_of(sel))
## 
## See <https://tidyselect.r-lib.org/reference/faq-external-vector.html>.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
## Joining with `by = join_by(CRIT_MIN)`
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.'"
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))
## Warning: Vectorized input to `element_text()` is not officially supported.
## ℹ Results may be unexpected or may change in future versions of ggplot2.
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."
p2b <- sources_imported_as_piv |>
    filter(!is.na(src) & DEPENDENCE == "Very 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,
         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))
## Warning: Vectorized input to `element_text()` is not officially supported.
## ℹ Results may be unexpected or may change in future versions of ggplot2.
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))
## Warning: Vectorized input to `element_text()` is not officially supported.
## ℹ Results may be unexpected or may change in future versions of ggplot2.
p2a

p2b

p2c

p2d

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")
palette <- brewer.pal(n = 8, name = "Dark2")
col <-palette[1:4]
fil <- palette[1:4]
key_stats_df[,2:4] <- lapply(key_stats_df[,2:4], as.numeric)
title_str <- "Of the Critical Minerals Identified by the US Geological Survey,"
cap_str <- "TK"
p6 <- key_stats_df |>
    ggplot(aes(x = x, y = y)) +
    geom_point(aes(size = as.numeric(percent),
                   color = as.factor(Quad), fill = as.factor(Quad))) +
    geom_text(aes(label = Label), fontface = "bold", color = "white",
              size = 14/.pt) +
    scale_size(range = c(15, 40)) +
    scale_fill_manual(values = fil) +
    scale_color_manual(values = col) +
    ylim(0, 1) + 
    xlim(0, 1) +
    theme_minimal() +
    theme(legend.position = "none",
          axis.text = element_blank(),
          axis.title = element_blank(),
          panel.grid = element_blank())
p6

ggsave("p6.png", plot = p6, scale = 0.8, dpi = 300, device = "png", bg = "transparent")
## Saving 5.6 x 4 in image
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

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

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
## Warning: Removed 1 rows containing missing values (`geom_text()`).

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()
p4c