top of page

Tesla EV Market Dashboard - Washington State

  • nalwogaimmaculate3
  • Nov 19, 2025
  • 3 min read

Toolset: R (tidyverse, dplyr, ggplot2, flexdasboard)


Overview

This project explores Tesla's market share and performance across Washington State using public EV registration data. Built in R with Flexdashboard, it delivers executivr-ready insights through interactive charts and curated summaries.


What I Did

  • Cleaned and filtered large datsets using dplyr and tidyverse

  • Visualized Tesla's market share, top models, and utility distribution using ggplot2

  • Compared Tesla vs competitors on electric range and MSRP

  • Explored trends in BEV and PHEV adoption

  • Identified top electric utilities serving Tesla owners


# DATA CLEANING


library(dplyr)
library(tidyr)
library(ggplot2)
library(scales)

df <- read.csv("C:\\Users\\nalwo\\OneDrive\\Documents\\R\\PROJECTS\\Electric_Vehicle_Population_Data.csv")
df


clean_df <- df %>%
  rename_all(~ gsub("\\.","_",.)) %>%
  mutate(
    Base_MSRP = as.numeric(Base_MSRP),
    Tesla = ifelse(Make == "TESLA", "TESLA", "COMPETITOR")
    )

  1. What percentage of EVs in Washington are Teslas?


total_vehicles <- nrow(clean_df)
total_no_teslas <- clean_df %>%
 filter(Tesla == "TESLA") %>% nrow()
Tesla_market_share <- round(total_no_teslas/total_vehicles * 100, 1)
market_df <- data.frame(Group = c("TESLA", "COMPETITOR"),

  Market_Share = c(Tesla_market_share, 100 - Tesla_market_share)
)
 
 market_df <- market_df %>%
  mutate(
  Label = paste0(Market_Share, "%"),
  ypos = cumsum(Market_Share) - 0.5 * Market_Share
  )
 
ggplot(market_df, aes(x = "", y = Market_Share, fill = Group)) +
  geom_col(width = 1) +
  coord_polar("y") +
  geom_text(aes(y =ypos, label = Label)) +
  labs(title = "Tesla Market Share in Wahington (%)" ) +
  theme_void()

2. Top Tesla Models Selling in the area

make_model_sold <-  clean_df %>%
  filter(Tesla == "TESLA") %>%
  group_by(Make, Model) %>%
  summarise(count_sold = n(), .groups = "drop") %>%
  arrange(desc(count_sold))

ggplot(make_model_sold, aes(x= reorder(Model, count_sold), y = count_sold)) +
  geom_col(fill = "dodgerblue") +
  coord_flip() +
  labs(title = "Tesla Models Sold - All Time") +
  theme_minimal()

3 . How much are we making from these models?

 
 make_model_sold <-  clean_df %>%
  filter(Tesla == "TESLA") %>%
  group_by(Make, Model) %>%
  summarise(count_sold = n(), .groups = "drop") %>%
  arrange(desc(count_sold))

ggplot(make_model_sold, aes(x= reorder(Model, count_sold), y = count_sold)) +
  geom_col(fill = "pink2") +
  coord_flip() +
  labs(title = "Tesla Models Sold - All Time") +
  theme_minimal()

# This dataset does not have good base msrp data - supplementing with online mrsp data

df_tesla_prices <- read.csv("C:\\Users\\nalwo\\OneDrive\\Documents\\R\\PROJECTS\\Tesla_Current_Base_Prices.csv")


# Transform data to upper case
df_tesla_prices <- df_tesla_prices %>%
  mutate(
    Model = toupper(Model
  )

# Getting the numbers 
Top_tesla_models<- make_model_sold %>%
  left_join(df_tesla_prices, by = "Model") %>%
  mutate(
    Estimated_revenue = as.numeric(count_sold) * as.numeric(Base_Price_USD)

  )


# FINAL ESTIMATES FOR LIFETIME SALES
Top_tesla_models_priced <- Top_tesla_models %>%
  filter(!is.na(Estimated_revenue)) %>%
  group_by(Model) %>%
  slice_min(Base_Price_USD) %>%
  ungroup() %>%
  arrange(desc(Estimated_revenue))

ggplot(Top_tesla_models_priced, aes(x = reorder(Model, Estimated_revenue), y= Estimated_revenue)) +
  geom_col(fill = "darkcyan") +
  coord_flip() +
  labs(title = "Estimated Revenue Per Model") +
  scale_y_continuous(labels = label_comma()) +
  theme_minimal()

  1. Tesla Vehicles Sold by Year


tesla_sold_by_year <- clean_df %>%
  filter(Tesla == "TESLA") %>%
  group_by(Model_Year) %>%
  summarise(Count = n()) %>%
  arrange(Model_Year)

ggplot(tesla_sold_by_year, aes(x = Model_Year, y= Count)) + 
  geom_line(color = "darkcyan", size = 1.1) +
  geom_point(color = "red", size = 2) +
  labs(title = "Tesla Vehicles Sold by Year") +
  theme_minimal()
  1. Tesla vs Competitors - Range and MSRP


#AVG MSRP

AVG_MSRP_for_EVs <- clean_df %>%
  filter(Electric_Vehicle_Type == "Battery Electric Vehicle (BEV)", Electric_Range != 0, Base_MSRP != 0) %>%
  group_by(Tesla) %>%
  summarize(AVG_Range = mean(Electric_Range),
            AVG_Msrp = mean(Base_MSRP))

ggplot(AVG_MSRP_for_EVs, aes(x= Tesla, y = AVG_Msrp, fill = Tesla)) + 
geom_col() +
labs(title = "AVG Electric MSRP (BEV)") +
theme_minimal()
  1. PHEV vs BEV Trends


PHEV_vs_BEV <- clean_df %>%
  group_by(Model_Year, Electric_Vehicle_Type) %>%
  summarise(Count = n(), .groups = "drop") %>%
  arrange(desc(Count))

ggplot(PHEV_vs_BEV, aes(x = Model_Year, y= Count, color = Electric_Vehicle_Type )) + 
  geom_line(size = 1.1) +
  geom_point( size = 2) +
  labs(title = "PHEV vs BEV Trends Over Time") +
  theme(axis.text.y = element_text(size = 4))+
  theme_minimal()
  1. Top Electric Utilities in Washington for Tesla


Utiliy_Count_for_Teslas <- clean_df %>%
  filter(Tesla == "TESLA") %>%
  group_by(Electric_Utility) %>%
  summarise(Count = n(), .groups = "drop") %>%
  arrange(desc(Count)) %>%
 head(10)

ggplot(Utiliy_Count_for_Teslas,aes(x = reorder(Electric_Utility, Count), y = Count)) +
  geom_col(fill = "darkcyan") +
  coord_flip() +
  labs(title = "Top Electric Utilities for Tesla in Washington ", x = "Utility", y = "Tesla Count") +
  theme_minimal() +
  theme(axis.text.y = element_text(size = 4))





 
 
 

Comments


bottom of page