Using Leaflet to tell the story of the electric vehicle charging network in Virginia

Story: Exploring electric vehicle charging density by network in Virginia

There are a myriad of charging networks in the United States that are akk competing to be the main provider of the growing electric vehicle market. Virginia is no exception and contains hundreds of public and privately accessible electric vehicle charging. With about 70% of charging happens at home the market for servicing electric vehicles with power is competitive and complex.

This map explores the questions of what is the electric vehicle charging density by network? Investigating this question will give insight in to the charging landscape of Virginia and shed light on who is winning the charging race. Charging density is defined in this project as the concentrations and territories of the charging providers. Results will inform further research like exploring the areas of Virginia that are not being served by these charging networks.

Data Preparation

Electric vehicle charigng data was obtained from the US Department of Energy’s Alternative Fuel Data Center, which provides a Alternative Fuel Stations Locator tool. Publically accessible data on the existing charging network was filtered to Virginia through the interactive webservice before being downloaded as a .csv.

In preparation for the data visualization used later in this project the Leaflet package was downloaded and added to the project.

library(leaflet)
library(sf)
## Linking to GEOS 3.12.2, GDAL 3.9.3, PROJ 9.4.1; sf_use_s2() is TRUE
library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr     1.1.4     ✔ readr     2.1.5
## ✔ forcats   1.0.0     ✔ stringr   1.5.1
## ✔ ggplot2   3.5.1     ✔ tibble    3.2.1
## ✔ lubridate 1.9.4     ✔ tidyr     1.3.1
## ✔ purrr     1.0.2
## ── 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(dplyr)

Reading data and creating a sptail object

# Electric vehicle charging station data was obtained from the US Department of Energy's Alternative Fuel Data Center's Fuel Locator tool.
altfuelst <- read.csv(file = "C:/GEOG588/Week4/data/alt_fuel_stations.csv")
glimpse(altfuelst)
## Rows: 2,029
## Columns: 75
## $ Fuel.Type.Code                          <chr> "ELEC", "ELEC", "ELEC", "ELEC"…
## $ Station.Name                            <chr> "Hotel Floyd", "Passport Nissa…
## $ Street.Address                          <chr> "120 Wilson St", "150 S Picket…
## $ Intersection.Directions                 <chr> "", "", "", "", "", "", "", "I…
## $ City                                    <chr> "Floyd", "Alexandria", "Chanti…
## $ State                                   <chr> "VA", "VA", "VA", "VA", "VA", …
## $ ZIP                                     <int> 24091, 22304, 20151, 22901, 22…
## $ Plus4                                   <lgl> NA, NA, NA, NA, NA, NA, NA, NA…
## $ Station.Phone                           <chr> "540-745-6080", "703-823-9000"…
## $ Status.Code                             <chr> "E", "E", "E", "E", "E", "E", …
## $ Expected.Date                           <chr> "", "", "", "", "", "", "", ""…
## $ Groups.With.Access.Code                 <chr> "Public", "Public - Call ahead…
## $ Access.Days.Time                        <chr> "8am-10pm daily; guest use onl…
## $ Cards.Accepted                          <chr> "", "", "", "", "", "", "", ""…
## $ BD.Blends                               <lgl> NA, NA, NA, NA, NA, NA, NA, NA…
## $ NG.Fill.Type.Code                       <lgl> NA, NA, NA, NA, NA, NA, NA, NA…
## $ NG.PSI                                  <lgl> NA, NA, NA, NA, NA, NA, NA, NA…
## $ EV.Level1.EVSE.Num                      <int> NA, NA, NA, NA, NA, NA, NA, 4,…
## $ EV.Level2.EVSE.Num                      <int> 1, 3, 2, 2, 1, 2, 2, NA, 1, 1,…
## $ EV.DC.Fast.Count                        <int> NA, 1, 1, 1, 1, 1, 1, NA, 1, 1…
## $ EV.Other.Info                           <lgl> NA, NA, NA, NA, NA, NA, NA, NA…
## $ EV.Network                              <chr> "Non-Networked", "Non-Networke…
## $ EV.Network.Web                          <chr> "", "", "", "", "", "", "", ""…
## $ Geocode.Status                          <chr> "200-9", "200-8", "200-8", "GP…
## $ Latitude                                <dbl> 36.91058, 38.80967, 38.89980, …
## $ Longitude                               <dbl> -80.31736, -77.12219, -77.4603…
## $ Date.Last.Confirmed                     <chr> "10/11/2024", "2/12/2024", "2/…
## $ ID                                      <int> 39514, 39763, 39764, 39765, 39…
## $ Updated.At                              <chr> "2024-10-11 18:09:31 UTC", "20…
## $ Owner.Type.Code                         <chr> "P", "P", "P", "P", "P", "P", …
## $ Federal.Agency.ID                       <int> NA, NA, NA, NA, NA, NA, NA, NA…
## $ Federal.Agency.Name                     <chr> "", "", "", "", "", "", "", ""…
## $ Open.Date                               <chr> "6/1/2011", "3/15/2011", "3/15…
## $ Hydrogen.Status.Link                    <lgl> NA, NA, NA, NA, NA, NA, NA, NA…
## $ NG.Vehicle.Class                        <lgl> NA, NA, NA, NA, NA, NA, NA, NA…
## $ LPG.Primary                             <lgl> NA, NA, NA, NA, NA, NA, NA, NA…
## $ E85.Blender.Pump                        <lgl> NA, NA, NA, NA, NA, NA, NA, NA…
## $ EV.Connector.Types                      <chr> "J1772", "CHADEMO J1772 J1772C…
## $ Country                                 <chr> "US", "US", "US", "US", "US", …
## $ Intersection.Directions..French.        <lgl> NA, NA, NA, NA, NA, NA, NA, NA…
## $ Access.Days.Time..French.               <lgl> NA, NA, NA, NA, NA, NA, NA, NA…
## $ BD.Blends..French.                      <lgl> NA, NA, NA, NA, NA, NA, NA, NA…
## $ Groups.With.Access.Code..French.        <chr> "Public", "Public - Appeler à …
## $ Hydrogen.Is.Retail                      <lgl> NA, NA, NA, NA, NA, NA, NA, NA…
## $ Access.Code                             <chr> "public", "public", "public", …
## $ Access.Detail.Code                      <chr> "", "CALL", "CALL", "CALL", "C…
## $ Federal.Agency.Code                     <chr> "", "", "", "", "", "", "", ""…
## $ Facility.Type                           <chr> "HOTEL", "CAR_DEALER", "CAR_DE…
## $ CNG.Dispenser.Num                       <lgl> NA, NA, NA, NA, NA, NA, NA, NA…
## $ CNG.On.Site.Renewable.Source            <lgl> NA, NA, NA, NA, NA, NA, NA, NA…
## $ CNG.Total.Compression.Capacity          <lgl> NA, NA, NA, NA, NA, NA, NA, NA…
## $ CNG.Storage.Capacity                    <lgl> NA, NA, NA, NA, NA, NA, NA, NA…
## $ LNG.On.Site.Renewable.Source            <lgl> NA, NA, NA, NA, NA, NA, NA, NA…
## $ E85.Other.Ethanol.Blends                <lgl> NA, NA, NA, NA, NA, NA, NA, NA…
## $ EV.Pricing                              <chr> "Free for guests; $10 for non-…
## $ EV.Pricing..French.                     <lgl> NA, NA, NA, NA, NA, NA, NA, NA…
## $ LPG.Nozzle.Types                        <lgl> NA, NA, NA, NA, NA, NA, NA, NA…
## $ Hydrogen.Pressures                      <lgl> NA, NA, NA, NA, NA, NA, NA, NA…
## $ Hydrogen.Standards                      <lgl> NA, NA, NA, NA, NA, NA, NA, NA…
## $ CNG.Fill.Type.Code                      <lgl> NA, NA, NA, NA, NA, NA, NA, NA…
## $ CNG.PSI                                 <lgl> NA, NA, NA, NA, NA, NA, NA, NA…
## $ CNG.Vehicle.Class                       <lgl> NA, NA, NA, NA, NA, NA, NA, NA…
## $ LNG.Vehicle.Class                       <lgl> NA, NA, NA, NA, NA, NA, NA, NA…
## $ EV.On.Site.Renewable.Source             <chr> "", "", "", "", "", "", "", ""…
## $ Restricted.Access                       <lgl> TRUE, FALSE, FALSE, FALSE, FAL…
## $ RD.Blends                               <lgl> NA, NA, NA, NA, NA, NA, NA, NA…
## $ RD.Blends..French.                      <lgl> NA, NA, NA, NA, NA, NA, NA, NA…
## $ RD.Blended.with.Biodiesel               <lgl> NA, NA, NA, NA, NA, NA, NA, NA…
## $ RD.Maximum.Biodiesel.Level              <lgl> NA, NA, NA, NA, NA, NA, NA, NA…
## $ NPS.Unit.Name                           <chr> "", "", "", "", "", "", "", ""…
## $ CNG.Station.Sells.Renewable.Natural.Gas <lgl> NA, NA, NA, NA, NA, NA, NA, NA…
## $ LNG.Station.Sells.Renewable.Natural.Gas <lgl> NA, NA, NA, NA, NA, NA, NA, NA…
## $ Maximum.Vehicle.Class                   <chr> "LD", "LD", "LD", "LD", "LD", …
## $ EV.Workplace.Charging                   <lgl> FALSE, FALSE, FALSE, FALSE, FA…
## $ Funding.Sources                         <lgl> NA, NA, NA, NA, NA, NA, NA, NA…
# Virginia county boundaries were acquired from the Virginia Open Data Portal. 
va_boundary <- read.csv(file = "C:/GEOG588/Week4/data/gis___virginia_county_boundaries_20240318.csv")
va_counties <- st_as_sf(x = va_boundary,
                        wkt = ("the_geom"),
                        crs = 4326)

# the "alt_stations" feature was made into a geospatial object through the "st_as_sf" function which reads the "Longitude" and "Latitude" coordinates of the station creating a point feature.
alt_stations <- st_as_sf(x = altfuelst,
                         coords = c("Longitude", "Latitude"),
                         crs = 4326)

# Palette
# A color palette was chosen to highlight the EV Netowkr providers, creating a visual distinction viewers can reference to understand the distribution of electric vehicle chargers in Virginia.
# Due to how many network providers there are a rainbow color scheme felt appropriate. Highlighting the wide range of services offered to Virginians and the number of companies competing for the growing EV market.
pal <- colorFactor(c(palette = "blue", "green", "yellow", "orange", "red"), domain = alt_stations$EV.Network)

Results

Map 1: Charging density in Virginia with point clustering

# Popupt text was created to assist the display of information when a user clicks on a specific charging site. 
popuptext <- sprintf("<b>Connecter Type: </b> %s", alt_stations$EV.Connector.Types)

# Map 1: Charging density in Virginia with point clustering
partB_map1 <- leaflet(data = alt_stations) %>%
  # CartoDB.DarkMatter Tiles were used to provide a highlight to Virginia's landscape.
  addProviderTiles(providers$CartoDB.DarkMatter) %>%
  # due to the dark background a white boundary for the county polygon helped make the layer standout.
  addPolygons(data = va_counties,
              fillColor = NA,
              fillOpacity = 1,
              color = "white",
              weight = 1,
              fill = NA) %>%
  # clusterOptions allows the user to cluster around a dataset. 
  addMarkers(clusterOptions = markerClusterOptions(showCoverageOnHover = TRUE),
             # popups can be detailed with the popup function. A "popuptext" object was created to assist with future edits of popup information.
             popup = popuptext,
             label = ~EV.Network)
  
partB_map1

Map 1 Results Discussion:

Charging stations have a wide spatial distribution in Virginia, in addition to a variety of network providers. A clustering map was chosen for Map 1 in order to ease the viewer in to the complex ecosystem of network providers by first showing the main metropolitan areas where charging was located. This clustering map also mirrors the main population centers of Virginia, which makes sense as more people typically means more electric vehicles.

Map 2. Ditribution of charging stations by company in Virginia

# Creating a partB_map object to store the map inside. This assisted with calling and storing the map. This will also assist with compositing the plots if that is a goal of future projects.
partB_map2 <- leaflet(alt_stations) %>%
  addProviderTiles(providers$CartoDB.DarkMatter) %>%
  # adding the va_counties polygon with a white boundary to stand out.
  addPolygons(data = va_counties,
              fillColor = NA,
              fillOpacity = 1,
              color = "white",
              weight = 1,
              fill = NA) %>%
  # Adding circle markers to visualize the charging site locations.
  addCircleMarkers(color = "lightgrey",
                   # fill color was informed by the palette object created previously in the exercise. With EV.Network informing the color scheme.
                   fillColor = ~pal(EV.Network),
                   fillOpacity = 0.8,
                   radius = 5,
                   # the popuptext object created earlier allows for less type in the below line and easy reference if changes want to be made later.
                   popup = popuptext,
                   label = ~EV.Network) %>%
  # adding a legend for viewers to differentiate between the projected network sites
  addLegend(pal = pal, values = ~EV.Network, opacity = 0.8)
partB_map2

Map 2 Results Discussion:

This map displays the full ecosystem of electric vehicle chargers by network. The complex ecosystem is summarized by color. The red display for Tesla highlights the company’s dominance in the current landscape of electric vehicle charging. Next steps for a dataset like this would a user friendly drop down menu that would allow viewers to filter and search based on the network they are hoping to investigate. Currently this plot does a decent job in summarizing the density and market trends toward specific network providers.

Sources