HW 5

Author

Alyssa Anderson

Homework 5

# Setp up
options(repos = c(CRAN = "https://cran.rstudio.com/"))
install.packages("readr")
Installing package into 'C:/Users/alyss/AppData/Local/R/win-library/4.2'
(as 'lib' is unspecified)
package 'readr' successfully unpacked and MD5 sums checked

The downloaded binary packages are in
    C:\Users\alyss\AppData\Local\Temp\RtmpqmxmVf\downloaded_packages
install.packages("here")
Installing package into 'C:/Users/alyss/AppData/Local/R/win-library/4.2'
(as 'lib' is unspecified)
package 'here' successfully unpacked and MD5 sums checked

The downloaded binary packages are in
    C:\Users\alyss\AppData\Local\Temp\RtmpqmxmVf\downloaded_packages
library(here)
here() starts at C:/Users/alyss/OneDrive - Johns Hopkins/Desktop/MIEF Courses/Sustainable Finance/Users/alyss/OneDrive - Johns Hopkins/Desktop/MIEF Courses/Sustainable Finance
library(tidyverse)
── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
✔ dplyr     1.1.1     ✔ readr     2.1.5
✔ forcats   1.0.0     ✔ stringr   1.5.0
✔ ggplot2   3.4.1     ✔ tibble    3.2.1
✔ lubridate 1.9.2     ✔ tidyr     1.3.0
✔ purrr     1.0.1     
── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag()    masks stats::lag()
ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(readxl)
library(tidyverse)
library(writexl)
library(esquisse)

Question #1

# creating a file path 
path_to_sheet <- here("data_raw", "CM_Data_Explorer.xlsx")

#read in 2.3 EV sheet

read_EV_sheet <- partial(
  .f = read_excel,
  path = path_to_sheet,
  sheet = "2.3 EV",
  col_names = FALSE
)

# provide the range
sheet_header_EV <- read_EV_sheet(range = "A4:W5")
New names:
• `` -> `...1`
• `` -> `...2`
• `` -> `...3`
• `` -> `...4`
• `` -> `...5`
• `` -> `...6`
• `` -> `...7`
• `` -> `...8`
• `` -> `...9`
• `` -> `...10`
• `` -> `...11`
• `` -> `...12`
• `` -> `...13`
• `` -> `...14`
• `` -> `...15`
• `` -> `...16`
• `` -> `...17`
• `` -> `...18`
• `` -> `...19`
• `` -> `...20`
• `` -> `...21`
• `` -> `...22`
• `` -> `...23`
sheet_header_EV_processed <- sheet_header_EV |> 
  # transpose the data
  t() |>
  # turn it back into a tibble
  as_tibble() |>
  # make them meaningful
  rename(scenario = V1, year = V2) |>
  # fill scenario down
  fill(scenario) |>
  #insert "Current" at top
  replace_na(list(scenario = "Current Year"))
Warning: The `x` argument of `as_tibble.matrix()` must have unique column names if
`.name_repair` is omitted as of tibble 2.0.0.
ℹ Using compatibility `.name_repair`.
tech_scenario <- read_EV_sheet(range = "A7") |> 
  pull()
New names:
• `` -> `...1`
tech_info <- read_EV_sheet(range = "A8:W19")
New names:
• `` -> `...1`
• `` -> `...2`
• `` -> `...3`
• `` -> `...4`
• `` -> `...5`
• `` -> `...6`
• `` -> `...7`
• `` -> `...8`
• `` -> `...9`
• `` -> `...10`
• `` -> `...11`
• `` -> `...12`
• `` -> `...13`
• `` -> `...14`
• `` -> `...15`
• `` -> `...16`
• `` -> `...17`
• `` -> `...18`
• `` -> `...19`
• `` -> `...20`
• `` -> `...21`
• `` -> `...22`
• `` -> `...23`
# get column name 
tech_info_col_names <- names(tech_info)

#add names as a header
EV_sheet_headers_and_col_names <- sheet_header_EV_processed |> 
  add_column(tech_info_col_names = tech_info_col_names)

# pivoting data long 
tech_info_long <- tech_info |> 
  rename(indicator = `...1`) |> 
  pivot_longer(cols = -indicator,
               names_to = "tech_info_col_names") |> 
  add_column(tech_scenario)


# combine data
EV_combined_data <- tech_info_long |> 
  left_join(EV_sheet_headers_and_col_names, by = join_by(tech_info_col_names)) |> 
  filter(!is.na(year)) |> 
  mutate(year = as.integer(year)) |> 
  select(tech_scenario, indicator, scenario, year, value)


# create a function
tech_scenario_range <- "A7"
tech_info_range <- "A8:W19"

read_iea_EV_table <-
  function(tech_scenario_range, tech_info_range) {
    tech_scenario <-
      read_EV_sheet(range = tech_scenario_range) |>
      pull()
    
    tech_info <- read_EV_sheet(range = tech_info_range)
    
    tech_info_col_names <- names(tech_info)
    
    tech_info_long <- tech_info |>
      rename(indicator = `...1`) |>
      pivot_longer(cols = -indicator,
                   names_to = "tech_info_col_names") |>
      add_column(tech_scenario)
    
    EV_combined_data <- tech_info_long |>
      left_join(EV_sheet_headers_and_col_names, by = join_by(tech_info_col_names)) |>
      filter(!is.na(year)) |>
      # case_when is supercharged if else
      mutate(year = as.integer(year)) |>
      select(tech_scenario, indicator, scenario, year, value)
    
    EV_combined_data
  }

# reading in charts
nickle_supply_table <- read_iea_EV_table(
  tech_scenario_range = "A7",
  tech_info_range = "A8:W19"
)
New names:
New names:
• `` -> `...1`
silicon_table <- read_iea_EV_table(
  tech_scenario_range = "A22",
  tech_info_range = "A23:W34"
)
New names:
New names:
• `` -> `...1`
batteries_table <- read_iea_EV_table(
  tech_scenario_range = "A37",
  tech_info_range = "A38:W49"
)
New names:
New names:
• `` -> `...1`
low_battery_table <- read_iea_EV_table(
  tech_scenario_range = "A52",
  tech_info_range = "A53:W64"
)
New names:
New names:
• `` -> `...1`
limited_battery_table <- read_iea_EV_table(
  tech_scenario_range = "A67",
  tech_info_range = "A68:W79"
)
New names:
New names:
• `` -> `...1`
base_case_table <- read_iea_EV_table(
  tech_scenario_range = "A82",
  tech_info_range = "A83:W94"
)
New names:
New names:
• `` -> `...1`
# binding rows 
final_iea_EV_table <- nickle_supply_table |> 
  bind_rows(silicon_table) |> 
  bind_rows(batteries_table) |>
  bind_rows(low_battery_table) |>
  bind_rows(limited_battery_table) |>
  bind_rows(base_case_table)

final_iea_EV_table
# A tibble: 1,368 × 5
   tech_scenario             indicator scenario                    year value
   <chr>                     <chr>     <chr>                      <int> <dbl>
 1 Constrained nickel supply Copper    Current Year                2022  381.
 2 Constrained nickel supply Copper    Stated policies scenario    2025  617.
 3 Constrained nickel supply Copper    Stated policies scenario    2030 1389.
 4 Constrained nickel supply Copper    Stated policies scenario    2035 1736.
 5 Constrained nickel supply Copper    Stated policies scenario    2040 2233.
 6 Constrained nickel supply Copper    Stated policies scenario    2045 2418.
 7 Constrained nickel supply Copper    Stated policies scenario    2050 2313.
 8 Constrained nickel supply Copper    Announced pledges scenario  2025  732.
 9 Constrained nickel supply Copper    Announced pledges scenario  2030 2113.
10 Constrained nickel supply Copper    Announced pledges scenario  2035 3587.
# ℹ 1,358 more rows
# write the data out 
write_csv(final_iea_EV_table,here("data_clean", "iea_mineral_demand_for_EV_vehicles.csv"))

Data Visualization #1

ggplot(final_iea_EV_table) +
  aes(x = indicator, y = value, colour = tech_scenario) +
  geom_col(fill = "#112446") +
  scale_color_hue(direction = 1) +
  labs(
    x = "Critical Mineral",
    y = "Thousands of Tons (kt)",
    title = "EV Vehicle Mineral Demand ",
    subtitle = "Copper and Graphite Have the Highest Demand of the Minerals",
    caption = "Data from IEA | Insights by Alyssa Anderson",
    color = "Possible Demand Scenarios"
  ) +
  theme_minimal()+
    theme(axis.text.x = element_text(angle = 45, hjust = .8))
Warning: Removed 144 rows containing missing values (`position_stack()`).

Data Visualization #2

ggplot(final_iea_EV_table) +
  aes(x = scenario, y = value, colour = indicator) +
  geom_col(fill = "#112446") +
  scale_fill_distiller() +
  labs(
    x = "Demand by Scenario",
    y = "Thousands of Tons (Kt)",
    title = "EV Mineral Demand By Scenario",
    subtitle = "Demand for Critical Minerals is Highest in a Net Zeros by 2050 Scenario",
    caption = "Data from IEA | Insights by Alyssa Anderson",
    color = "Critical Mineral"
  ) +
  theme_minimal()+
  theme(legend.position = "none")+
  theme(axis.text.x = element_text(angle = 45, hjust = 1, size = 7 ))
Warning: Removed 144 rows containing missing values (`position_stack()`).

Data Visualization #3

filtered_graphite <- final_iea_EV_table %>%
  filter(indicator == "Graphite")

ggplot(filtered_graphite, aes(y = tech_scenario, x = value)) +
  geom_col(fill= "grey") +  
  labs(title = "Graphite Demand by Scenario",
       subtitle = "Graphite Demand Will Lessen if Batteries Get Smaller",
       caption = "Data from IEA | Insights by Alyssa Anderson",
       y = "Scenario",
       x = "Graphite Demand (kt)") +
  theme_minimal()
Warning: Removed 12 rows containing missing values (`position_stack()`).

Data Visualization #4

filtered_copper <- final_iea_EV_table %>%
  filter(indicator == "Copper")

ggplot(filtered_copper, aes(y = tech_scenario, x = value)) +
  geom_col(fill= "#B87333") +  
  labs(title = "Copper Demand by Scenario",
       subtitle = "Copper Demand is Highest with Constrained Nickle Supply",
       caption = "Data from IEA | Insights by Alyssa Anderson",
       y = "Scenario",
       x = "Copper Demand (kt)") +
  theme_minimal()
Warning: Removed 12 rows containing missing values (`position_stack()`).

Data Visualization #5

filtered_copper_graphite <- final_iea_EV_table %>%
  filter(indicator == "Copper" | indicator == "Graphite")

ggplot(filtered_copper_graphite) +
  aes(x = value, y = tech_scenario, colour = indicator) +
  geom_boxplot(fill = "#112446") +
  scale_color_manual(
    values = c(Copper = "#B87333",
    Graphite = "#808080")
  ) +
  labs(
    x = "Graphite and Copper Demand (kt)",
    y = "Scenarios",
    title = "Comparison of Copper and Graphite Demand",
    subtitle = "Battery Size Reduction or Constrained Nickel Supply will Drive up Demand",
    caption = "Data from IEA | Insights by Alyssa Anderson",
    color = "Mineral"
  ) +
  theme_minimal()+
theme(
    plot.title = element_text(hjust = 0),  # Align title text to the left
    plot.title.position = "plot"  # Position title relative to the plot area
  )
Warning: Removed 24 rows containing non-finite values (`stat_boxplot()`).