Show the R libraries used
library(leaflet)
library(sf)
library(tidyverse)
library(RColorBrewer)
George Girton
May 25, 2024
TK, before starting here, created a national point layer of EV charger locations, and a level 8 hexagon polygon layer. The hexagon polygons layer was loaded into a Scan/US Desktop subscription, and used as a template to aggregate a data item “Vehicles available” for an area around San Francisco.
The two layers were exported as Shapefiles, which were then combined into the GeoPackage .gpkg file SF_TWO.gpkg GeoPackage website, to supposedly make life simpler.
The code section below reads that file into two map layers used by Leaflet in the next step
# Read the layers from the two-layer GeoPackage (.gpkg) file
Chargers <- st_read(paste0(here::here(),"/posts/ChargerMapSF/mapdata/SF_Two.gpkg"), layer = "May2024Chargers",quiet=TRUE)
Hex8 <- st_read(paste0(here::here(),"/posts/ChargerMapSF/mapdata/SF_Two.gpkg"), layer = "Hex8_SFpop",quiet=TRUE)
# Avoid the 'inconsistent datum' warning by transforming coordinates to EPSG:4326
Chargers <- st_transform(st_as_sf(Chargers),4326)
Hex8 <- st_transform(st_as_sf(Hex8),4326)
## Get a matching data file to the Charger locations data file, so we can put the station name or maybe some other data
ChargersData <- read.csv(paste0(here::here(),"/posts/ChargerMapSF/mapdata/SF_Chargers.csv"))
ChargersData$KEY= str_sub(ChargersData$KEY, start=2L)
ChargersLayer <- merge(Chargers, ChargersData, by.x = "KEY", by.y = "KEY")
# Read tiny demographic data file of just a few values, exported from Scan/US
HexData <- read.csv(paste0(here::here(),"/posts/ChargerMapSF/mapdata/SFHex8Data.csv"))
# Set the KEY field to match exactly by removing the octothorpe character, and no I am not making that up, from the key name
HexData$KEY= str_sub(HexData$KEY, start=2L)
# Merge the SF geography file 'Hex8' with the data file 'HexData' that matches it, and make a new geo file 'HexLayer' to use directly in leaflet.
HexLayer <- merge(Hex8, HexData, by.x="KEY", by.y = "KEY")
First, don’t make a thematic map. Just make a point map showing the charger locations (snail emoji: 🐌)
I started by trying to craft a palette manually, using the ‘cut’ function in base R. It turns out, due to one of the helper functions in the RColorBrewer package, did not need to do this at all:
# This was some "make your own palette" code that was given to me by the Mistral beta GPT, when I asked it why the palette code did not work.
# num_bins = 5
# HexLayer$range <- cut(HexLayer$TotalVehicles, breaks = num_bins, labels = FALSE)
# HexLayer$VehColor <- mypal[HexLayer$range]
# Create value-to-color mapping function
# There is a convenient helper function in RColorbrewer package do it for you!
First set up the palette by making a function that will translate the range of values in TotalVehicles into a particular palette color. You give it the data ‘domain’ so it can perform its own ‘cut’ and generate a palette for blue and purple, which is quaintly named ‘BuPu’. Then, with the ‘bluepurpal()’ function, call the function ON that column during “AddPolygons”.
# using colorBrewer's 'colorNumeric()', Make a function that will map the values in the TotalVehicles column to a palette
bluepurpal <- colorNumeric(palette="BuPu", domain=HexLayer$TotalVehicles)
#Create a choropleth map of the area layer using addPolygons inside the leaflet() function:
leaflet(HexLayer) |>
addTiles() |>
addPolygons(
fillColor = ~bluepurpal(TotalVehicles), # call the function to map TotalVehicles numbers to palette colors
fillOpacity = 0.7,
weight = 1,
popup = ~paste("Vehicles: ", HexLayer$TotalVehicles)) |>
addCircles(data = ChargersLayer,
weight = 4,
color = "red",
fill = FALSE,
#fillOpacity = 0.8,
popup = ~paste("Location name: ", ChargersLayer$StationName)
) |>
addLegend(pal = bluepurpal, # send the palette function to the legend too!
values = ~TotalVehicles, labFormat = labelFormat(
prefix = "[", suffix = "]", between = ", "
),position = "bottomright" )