Problem 1.1
Use the workflow developed in this chapter to import and tidy worksheet 2.3 EV from the dataset.
# The easiest way to get readr is to install the whole tidyverse:
options (repos = c (CRAN = "https://cran.rstudio.com/" ))
install.packages ("tidyverse" )
The downloaded binary packages are in
/var/folders/2p/9wzbkfqj1699rqy549yz78sh0000gn/T//Rtmp56Ea4I/downloaded_packages
# Alternatively, install just readr:
install.packages ("readr" )
The downloaded binary packages are in
/var/folders/2p/9wzbkfqj1699rqy549yz78sh0000gn/T//Rtmp56Ea4I/downloaded_packages
install.packages ("purrr" )
The downloaded binary packages are in
/var/folders/2p/9wzbkfqj1699rqy549yz78sh0000gn/T//Rtmp56Ea4I/downloaded_packages
install.packages ("readxl" )
The downloaded binary packages are in
/var/folders/2p/9wzbkfqj1699rqy549yz78sh0000gn/T//Rtmp56Ea4I/downloaded_packages
library (here) # for using relative file paths
here() starts at /Users/fangjun/Desktop/Sais/Year2/Term2/Sustainable Finance/W5/data-raw
library (purrr)
library (readxl)
library (tidyr)
library (dplyr)
Attaching package: 'dplyr'
The following objects are masked from 'package:stats':
filter, lag
The following objects are masked from 'package:base':
intersect, setdiff, setequal, union
── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
✔ forcats 1.0.0 ✔ readr 2.1.5
✔ ggplot2 3.4.4 ✔ stringr 1.5.1
✔ lubridate 1.9.3 ✔ tibble 3.2.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 (here)
path_to_sheet <- here ("CM_Data_Explorer.xlsx" )
path_to_sheet
[1] "/Users/fangjun/Desktop/Sais/Year2/Term2/Sustainable Finance/W5/data-raw/CM_Data_Explorer.xlsx"
library (purrr)
library (readxl)
read_EV_sheet <- partial (
# provide the function, in this case readxl::read_excel()
.f = read_excel,
# provide any arguments you want filled in
path = path_to_sheet,
sheet = "2.3 EV" ,
col_names = FALSE
)
# now all we have to do is provide the range
sheet_header <- 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`
# A tibble: 2 × 23
...1 ...2 ...3 ...4 ...5 ...6 ...7 ...8 ...9 ...10 ...11 ...12 ...13
<lgl> <dbl> <lgl> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <lgl> <chr> <dbl> <dbl>
1 NA NA NA State… NA NA NA NA NA NA Anno… NA NA
2 NA 2022 NA 2025 2030 2035 2040 2045 2050 NA 2025 2030 2035
# ℹ 10 more variables: ...14 <dbl>, ...15 <dbl>, ...16 <dbl>, ...17 <lgl>,
# ...18 <chr>, ...19 <dbl>, ...20 <dbl>, ...21 <dbl>, ...22 <dbl>,
# ...23 <dbl>
library (tidyr)
library (dplyr)
sheet_header_processed <- sheet_header |>
# transpose the data
t () |>
# turn it back into a tibble
as_tibble () |>
# make them meaningful
rename (scenario = V1, year = V2) |>
# fill scenario down: If there are any NA (missing) values in the scenario column, this function will fill those NA values with the last observed non-NA value above them
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`.
# A tibble: 23 × 2
scenario year
<chr> <chr>
1 Current Year <NA>
2 Current Year 2022
3 Current Year <NA>
4 Stated policies scenario 2025
5 Stated policies scenario 2030
6 Stated policies scenario 2035
7 Stated policies scenario 2040
8 Stated policies scenario 2045
9 Stated policies scenario 2050
10 Stated policies scenario <NA>
# ℹ 13 more rows
EV_name <- read_EV_sheet (range = "A7" ) |>
pull ()
New names:
• `` -> `...1`
[1] "Constrained nickel supply"
EV_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`
# A tibble: 12 × 23
...1 ...2 ...3 ...4 ...5 ...6 ...7 ...8 ...9 ...10
<chr> <dbl> <lgl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <lgl>
1 Copper 3.81e+2 NA 6.17e+2 1.39e+3 1.74e+3 2.23e+3 2.42e+3 2.31e+3 NA
2 Cobalt 6.35e+1 NA 6.12e+1 3.80e+1 2.91e+1 3.54e+1 4.09e+1 4.74e+1 NA
3 Graphite 5.57e+2 NA 9.36e+2 1.59e+3 1.78e+3 1.69e+3 1.49e+3 1.08e+3 NA
4 Lithium 6.96e+1 NA 1.23e+2 2.19e+2 3.07e+2 4.07e+2 4.50e+2 4.13e+2 NA
5 Manganese 7.45e+1 NA 5.39e+1 1.56e+2 3.36e+2 5.33e+2 7.12e+2 8.58e+2 NA
6 Nickel 3.13e+2 NA 5.54e+2 5.13e+2 5.89e+2 6.30e+2 6.92e+2 6.88e+2 NA
7 Silicon 8.70e+0 NA 4.05e+1 1.39e+2 2.24e+2 3.52e+2 3.74e+2 3.73e+2 NA
8 Neodymium 3.96e+0 NA 7.25e+0 1.22e+1 1.51e+1 1.88e+1 2.18e+1 2.29e+1 NA
9 Dysprosi… 4.13e-1 NA 7.41e-1 1.21e+0 1.48e+0 1.84e+0 2.13e+0 2.23e+0 NA
10 Praseody… 5.94e-1 NA 1.09e+0 1.83e+0 2.27e+0 2.83e+0 3.27e+0 3.43e+0 NA
11 Terbium 8.06e-2 NA 1.48e-1 2.52e-1 3.14e-1 3.91e-1 4.52e-1 4.74e-1 NA
12 Total EV 1.47e+3 NA 2.39e+3 4.06e+3 5.02e+3 5.91e+3 6.21e+3 5.80e+3 NA
# ℹ 13 more variables: ...11 <dbl>, ...12 <dbl>, ...13 <dbl>, ...14 <dbl>,
# ...15 <dbl>, ...16 <dbl>, ...17 <lgl>, ...18 <dbl>, ...19 <dbl>,
# ...20 <dbl>, ...21 <dbl>, ...22 <dbl>, ...23 <dbl>
library (tidyverse)
EV_info_col_names <- names (EV_info)
EV_info_col_names
[1] "...1" "...2" "...3" "...4" "...5" "...6" "...7" "...8" "...9"
[10] "...10" "...11" "...12" "...13" "...14" "...15" "...16" "...17" "...18"
[19] "...19" "...20" "...21" "...22" "...23"
sheet_headers_and_col_names <- sheet_header_processed |>
add_column (EV_info_col_names = EV_info_col_names)
sheet_headers_and_col_names
# A tibble: 23 × 3
scenario year EV_info_col_names
<chr> <chr> <chr>
1 Current Year <NA> ...1
2 Current Year 2022 ...2
3 Current Year <NA> ...3
4 Stated policies scenario 2025 ...4
5 Stated policies scenario 2030 ...5
6 Stated policies scenario 2035 ...6
7 Stated policies scenario 2040 ...7
8 Stated policies scenario 2045 ...8
9 Stated policies scenario 2050 ...9
10 Stated policies scenario <NA> ...10
# ℹ 13 more rows
EV_info_long <- EV_info |>
rename (indicator = ` ...1 ` ) |>
pivot_longer (cols = - indicator,
names_to = "EV_info_col_names" ) |>
add_column (EV_name)
EV_info_long
# A tibble: 264 × 4
indicator EV_info_col_names value EV_name
<chr> <chr> <dbl> <chr>
1 Copper ...2 381. Constrained nickel supply
2 Copper ...3 NA Constrained nickel supply
3 Copper ...4 617. Constrained nickel supply
4 Copper ...5 1389. Constrained nickel supply
5 Copper ...6 1736. Constrained nickel supply
6 Copper ...7 2233. Constrained nickel supply
7 Copper ...8 2418. Constrained nickel supply
8 Copper ...9 2313. Constrained nickel supply
9 Copper ...10 NA Constrained nickel supply
10 Copper ...11 732. Constrained nickel supply
# ℹ 254 more rows
combined_data <- EV_info_long |>
left_join (sheet_headers_and_col_names, by = join_by (EV_info_col_names)) |>
# filter out what were empty columns (where years are NA)
#There's a blannk column in Excel
filter (! is.na (year)) |>
# case_when is supercharged if else
mutate (unit = "kiloton" ,
# convert the year column from character to numeric
year = as.integer (year)
) |>
select (EV_name, indicator, scenario, unit, year, value)
combined_data
# A tibble: 228 × 6
EV_name indicator scenario unit year value
<chr> <chr> <chr> <chr> <int> <dbl>
1 Constrained nickel supply Copper Current Year kilo… 2022 381.
2 Constrained nickel supply Copper Stated policies scenar… kilo… 2025 617.
3 Constrained nickel supply Copper Stated policies scenar… kilo… 2030 1389.
4 Constrained nickel supply Copper Stated policies scenar… kilo… 2035 1736.
5 Constrained nickel supply Copper Stated policies scenar… kilo… 2040 2233.
6 Constrained nickel supply Copper Stated policies scenar… kilo… 2045 2418.
7 Constrained nickel supply Copper Stated policies scenar… kilo… 2050 2313.
8 Constrained nickel supply Copper Announced pledges scen… kilo… 2025 732.
9 Constrained nickel supply Copper Announced pledges scen… kilo… 2030 2113.
10 Constrained nickel supply Copper Announced pledges scen… kilo… 2035 3587.
# ℹ 218 more rows
Building the function
EV_name_range <- "A7"
EV_info_range <- "A8:W19"
EV_name <- read_EV_sheet (range = EV_name_range) |>
pull ()
New names:
• `` -> `...1`
EV_info <- read_EV_sheet (range = EV_info_range)
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`
EV_info_col_names <- names (EV_info)
EV_info_long <- EV_info |>
rename (indicator = ` ...1 ` ) |>
pivot_longer (cols = - indicator,
names_to = "EV_info_col_names" ) |>
add_column (EV_name)
combined_data <- EV_info_long |>
left_join (sheet_headers_and_col_names, by = join_by (EV_info_col_names)) |>
# filter out what were empty columns (where years are NA)
filter (! is.na (year)) |>
# case_when is supercharged if else
mutate (unit = "kiloton" ,
# convert the year column from character to numeric
year = as.integer (year)
) |>
select (EV_name, indicator, scenario, unit, year, value)
combined_data
# A tibble: 228 × 6
EV_name indicator scenario unit year value
<chr> <chr> <chr> <chr> <int> <dbl>
1 Constrained nickel supply Copper Current Year kilo… 2022 381.
2 Constrained nickel supply Copper Stated policies scenar… kilo… 2025 617.
3 Constrained nickel supply Copper Stated policies scenar… kilo… 2030 1389.
4 Constrained nickel supply Copper Stated policies scenar… kilo… 2035 1736.
5 Constrained nickel supply Copper Stated policies scenar… kilo… 2040 2233.
6 Constrained nickel supply Copper Stated policies scenar… kilo… 2045 2418.
7 Constrained nickel supply Copper Stated policies scenar… kilo… 2050 2313.
8 Constrained nickel supply Copper Announced pledges scen… kilo… 2025 732.
9 Constrained nickel supply Copper Announced pledges scen… kilo… 2030 2113.
10 Constrained nickel supply Copper Announced pledges scen… kilo… 2035 3587.
# ℹ 218 more rows
read_iea_EV_table <-
function (EV_name_range, EV_info_range) {
EV_name <-
read_EV_sheet (range = EV_name_range) |>
pull ()
EV_info <- read_EV_sheet (range = EV_info_range)
EV_info_col_names <- names (EV_info)
EV_info_long <- EV_info |>
rename (indicator = ` ...1 ` ) |>
pivot_longer (cols = - indicator,
names_to = "EV_info_col_names" ) |>
add_column (EV_name)
combined_data <- EV_info_long |>
left_join (sheet_headers_and_col_names, by = join_by (EV_info_col_names)) |>
# filter out what were empty columns (where years are NA)
filter (! is.na (year)) |>
# case_when is supercharged if else
mutate (
unit = "kiloton" ,
# convert the year column from character to numeric
year = as.integer (year)
) |>
select (EV_name, indicator, scenario, unit, year, value)
combined_data
}
Constrained_nickel_supply_table <- read_iea_EV_table (
EV_name_range = "A7" ,
EV_info_range = "A8:W19"
)
New names:
New names:
• `` -> `...1`
Wider_use_of_silicon_rich_anodes_table <- read_iea_EV_table (
EV_name_range = "A22" ,
EV_info_range = "A23:W34"
)
New names:
New names:
• `` -> `...1`
Faster_uptake_of_solid_state_batteries_table <- read_iea_EV_table (
EV_name_range = "A37" ,
EV_info_range = "A38:W49"
)
New names:
New names:
• `` -> `...1`
Lower_battery_sizes_table <- read_iea_EV_table (
EV_name_range = "A52" ,
EV_info_range = "A53:W64"
)
New names:
New names:
• `` -> `...1`
Limited_battery_size_reduction_table <- read_iea_EV_table (
EV_name_range = "A67" ,
EV_info_range = "A68:W79"
)
New names:
New names:
• `` -> `...1`
STEPS_Base_case_table <- read_iea_EV_table (
EV_name_range = "A82" ,
EV_info_range = "A83:W94"
)
New names:
New names:
• `` -> `...1`
final_iea_EV_table <- Constrained_nickel_supply_table |>
bind_rows (Wider_use_of_silicon_rich_anodes_table) |>
bind_rows (Faster_uptake_of_solid_state_batteries_table) |>
bind_rows (Lower_battery_sizes_table) |>
bind_rows (Limited_battery_size_reduction_table) |>
bind_rows (STEPS_Base_case_table)
final_iea_EV_table
# A tibble: 1,368 × 6
EV_name indicator scenario unit year value
<chr> <chr> <chr> <chr> <int> <dbl>
1 Constrained nickel supply Copper Current Year kilo… 2022 381.
2 Constrained nickel supply Copper Stated policies scenar… kilo… 2025 617.
3 Constrained nickel supply Copper Stated policies scenar… kilo… 2030 1389.
4 Constrained nickel supply Copper Stated policies scenar… kilo… 2035 1736.
5 Constrained nickel supply Copper Stated policies scenar… kilo… 2040 2233.
6 Constrained nickel supply Copper Stated policies scenar… kilo… 2045 2418.
7 Constrained nickel supply Copper Stated policies scenar… kilo… 2050 2313.
8 Constrained nickel supply Copper Announced pledges scen… kilo… 2025 732.
9 Constrained nickel supply Copper Announced pledges scen… kilo… 2030 2113.
10 Constrained nickel supply Copper Announced pledges scen… kilo… 2035 3587.
# ℹ 1,358 more rows
Problem 1.1.2
library (dplyr)
library (ggplot2)
combined_data %>%
filter (indicator %in% c ("Cobalt" , "Copper" )) %>%
ggplot () +
aes (x = indicator, y = value, fill = indicator, colour = indicator) +
geom_col () +
scale_fill_manual (values = c (Cobalt = "#D6B067" , Copper = "#6BBEB3" )) +
scale_color_manual (values = c (Cobalt = "#D6B067" ,
Copper = "#6BBEB3" )) +
labs (x = "Indicator" , y = "Value" , title = "Copper vs. Cobalt Under Constrained Nickel Supply" ,
subtitle = "Copper takes the lead across policy scenarios" , caption = "Jun!" ) +
theme_minimal () +
facet_wrap (vars (scenario))
library (dplyr)
library (ggplot2)
Lower_battery_sizes_table %>%
filter (indicator %in% c ("Cobalt" , "Copper" )) %>%
filter (! (scenario %in%
"Current Year" )) %>%
ggplot () +
aes (x = year, y = value, fill = indicator, colour = indicator) +
geom_point (shape = "circle" , size = 1.75 ) +
geom_smooth (span = 0.85 ) +
scale_fill_hue (direction = 1 ) +
scale_color_hue (direction = 1 ) +
labs (x = "Year" , y = "Value" , title = "Copper vs. Cobalt under lower battery size scenario" ,
subtitle = "Copper takes the lead under three policy scenarios" , caption = "Jun!" ) +
theme (axis.text.x = element_text (angle = 45 , hjust = 1 , size = 8 )) +
theme_minimal () +
facet_wrap (vars (scenario))
`geom_smooth()` using method = 'loess' and formula = 'y ~ x'
final_iea_EV_table %>%
filter (indicator %in% c ("Cobalt" , "Copper" )) %>%
filter (scenario %in% "Net Zero Emissions by 2050 scenario" ) %>%
ggplot () +
aes (
x = year,
y = value,
fill = indicator,
colour = indicator
) +
geom_line () +
scale_fill_hue (direction = 1 ) +
scale_color_hue (direction = 1 ) +
labs (
x = "Year" ,
y = "Value" ,
title = "Copper vs. Cobalt under net zero emission scenario" ,
subtitle = "Copper takes the lead and reach peak before 2045" ,
caption = "Jun!"
) +
theme_minimal () +
theme (axis.text.x = element_text (angle = 45 , hjust = 1 , size = 8 )) +
facet_wrap (vars (EV_name))
Faster_uptake_of_solid_state_batteries_table %>%
filter (indicator %in% c ("Cobalt" , "Copper" )) %>%
filter (scenario %in%
c ("Stated policies scenario" , "Current Year" )) %>%
ggplot () +
aes (x = year, y = value, colour = indicator) +
geom_point (shape = "circle" , size = 1.5 ) +
geom_smooth (span = 0.75 ) +
scale_color_hue (direction = 1 ) +
labs (x = "Year" , y = "Value" , title = "Copper vs. Cobalt under faster uptake of solid state batteries scenario" ,
caption = "Jun!" ) +
theme_minimal ()
`geom_smooth()` using method = 'loess' and formula = 'y ~ x'
library (dplyr)
library (ggplot2)
final_iea_EV_table %>%
filter (indicator %in% c ("Cobalt" , "Copper" )) %>%
filter (scenario %in% "Announced pledges scenario" ) %>%
ggplot () +
aes (x = year, y = value, fill = indicator, colour = indicator) +
geom_point (shape = "circle" ,
size = 1.5 ) +
geom_smooth (span = 0.84 ) +
scale_fill_hue (direction = 1 ) +
scale_color_hue (direction = 1 ) +
labs (x = "Year" , y = "Value" , title = "Copper vs. Cobalt under announced pledge scenario" , subtitle = "The gap is widening" ,
caption = "Jun!" ) +
theme_minimal () +
facet_wrap (vars (EV_name))
`geom_smooth()` using method = 'loess' and formula = 'y ~ x'
Warning: Removed 12 rows containing non-finite values (`stat_smooth()`).
Warning: Removed 12 rows containing missing values (`geom_point()`).