Introduction

This project analyzes global electric vehicle adoption trends using publicly available datasets from the International Energy Agency (IEA). The visualizations focus on EV sales growth, market share, charging infrastructure, and country-wise comparisons.

Import Data

dat <- read_excel("EVDataExplorer2025.xlsx")

dat <- tibble(dat)

head(dat)
## # A tibble: 6 × 9
##   region_country category         parameter mode   powertrain  year unit   value
##   <chr>          <chr>            <chr>     <chr>  <chr>      <dbl> <chr>  <dbl>
## 1 World          Projection-STEPS EV stock  2 and… BEV         2030 Vehi… 1.7 e8
## 2 World          Projection-STEPS EV stock  Cars   BEV         2030 Vehi… 1.5 e8
## 3 China          Projection-STEPS EV stock  2 and… BEV         2030 Vehi… 9.1 e7
## 4 China          Projection-STEPS EV stock  Cars   BEV         2030 Vehi… 8.2 e7
## 5 World          Projection-STEPS EV stock  Cars   PHEV        2030 Vehi… 8.2 e7
## 6 World          Historical       EV stock  2 and… BEV         2024 Vehi… 7.90e7
## # ℹ 1 more variable: `Aggregate group` <chr>

Column Names

names(dat)
## [1] "region_country"  "category"        "parameter"       "mode"           
## [5] "powertrain"      "year"            "unit"            "value"          
## [9] "Aggregate group"

Visualization 1: Global EV Growth Over Time

viz1 <- dat %>%
  filter(parameter == "EV sales") %>%
  group_by(year) %>%
  summarise(total_sales = sum(value, na.rm = TRUE))

ggplot(viz1, aes(x = year, y = total_sales)) +
  geom_line(size = 1.2, color = "blue") +
  labs(
    title = "Global EV Sales Growth Over Time",
    x = "Year",
    y = "Total EV Sales"
  ) +
  theme_minimal()
## Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
## ℹ Please use `linewidth` instead.
## This warning is displayed once per session.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.

# Visualization 2: EV Sales by Country

viz2 <- dat %>%
  filter(parameter == "EV sales", year == max(year, na.rm = TRUE)) %>%
  group_by(region_country) %>%
  summarise(total_sales = sum(value, na.rm = TRUE)) %>%
  arrange(desc(total_sales)) %>%
  slice(1:10)

ggplot(viz2, aes(x = reorder(region_country, total_sales), y = total_sales)) +
  geom_col(fill = "darkgreen") +
  coord_flip() +
  labs(
    title = "Top 10 Countries by EV Sales",
    x = "Country",
    y = "EV Sales"
  ) +
  theme_minimal()

# Visualization 3: EV Powertrain Comparison

viz3 <- dat %>%
  filter(parameter == "EV sales") %>%
  group_by(powertrain) %>%
  summarise(total_sales = sum(value, na.rm = TRUE))

ggplot(viz3, aes(x = powertrain, y = total_sales)) +
  geom_col(fill = "orange") +
  labs(
    title = "EV Sales by Powertrain Type",
    x = "Powertrain",
    y = "Total Sales"
  ) +
  theme_minimal()

# Visualization 4: India EV Sales Trend

viz4 <- dat %>%
  filter(region_country == "India", parameter == "EV sales")

ggplot(viz4, aes(x = year, y = value)) +
  geom_line(color = "red", size = 1.2) +
  labs(
    title = "Electric Vehicle Sales Trend in India",
    x = "Year",
    y = "EV Sales"
  ) +
  theme_minimal()

# Visualization 5: EV Sales Distribution

viz5 <- dat %>%
  filter(parameter == "EV sales")

ggplot(viz5, aes(x = year, y = value)) +
  geom_point(alpha = 0.5, color = "purple") +
  labs(
    title = "Distribution of EV Sales",
    x = "Year",
    y = "EV Sales"
  ) +
  theme_minimal()

# Visualization 6: EV Sales Spread by Powertrain

viz6 <- dat %>%
  filter(parameter == "EV sales")

ggplot(viz6, aes(x = powertrain, y = value)) +
  geom_boxplot(fill = "skyblue") +
  labs(
    title = "Spread of EV Sales by Powertrain",
    x = "Powertrain",
    y = "Sales"
  ) +
  theme_minimal()

# Visualization 7: Heatmap of EV Sales

viz7 <- dat %>%
  filter(parameter == "EV sales") %>%
  group_by(region_country, year) %>%
  summarise(total_sales = sum(value, na.rm = TRUE))
## `summarise()` has regrouped the output.
## ℹ Summaries were computed grouped by region_country and year.
## ℹ Output is grouped by region_country.
## ℹ Use `summarise(.groups = "drop_last")` to silence this message.
## ℹ Use `summarise(.by = c(region_country, year))` for per-operation grouping
##   (`?dplyr::dplyr_by`) instead.
ggplot(viz7, aes(x = year, y = region_country, fill = total_sales)) +
  geom_tile() +
  scale_fill_viridis() +
  labs(
    title = "Heatmap of EV Sales by Country and Year",
    x = "Year",
    y = "Country"
  ) +
  theme_minimal()

# Visualization 8: Interactive EV Sales Trend

plot_ly(
  data = viz1,
  x = ~year,
  y = ~total_sales,
  type = 'scatter',
  mode = 'lines+markers'
) %>%
  layout(
    title = "Interactive Global EV Sales Trend",
    xaxis = list(title = "Year"),
    yaxis = list(title = "Total EV Sales")
  )