This is the supplementary notes and examples for an introduction to leaflet.
It is based on data and examples seen in class
Built on the excellent tutorial from RStudio
If not already installed, install leaflet
:
install.packages("leaflet")
Then attach the library:
library(leaflet)
Bring in the other needed libraries:
library(sf)
library(tidyverse)
library(USAboundaries)
Creating a Leaflet map requires a few basic steps (not dissimilar to ggplot):
Initialize a map widget by calling leaflet().
Add layers (i.e., features) to the map by using layer functions (e.g. addTiles, addMarkers, addPolygons,…)
Print the map widget to display it.
Here’s a basic example:
leaflet() %>%
addTiles() %>%
addMarkers(lng=-119.8489, lat=34.4140, popup="UCSB")
By default, leaflet sets the view of the map to the range of latitude/longitude data in the map layers
You can adjust these if needed using:
setView()
: sets the center of the map view and the zoom level;
fitBounds()
: fits the view into the rectangle [lng1, lat1] – [lng2, lat2];
clearBounds()
clears the bound
The easiest way to add tiles is by calling addTiles()
with no arguments; by default, OpenStreetMap tiles are used.
(leaflet() %>%
setView(lng=-119.8489, lat=34.4140, zoom = 12) %>%
addTiles())
Many third-party basemaps can be added using the addProviderTiles()
function
As a convenience, leaflet provides a named list of all the third-party tile providers supported by the plugin: just type providers$
and choose from one of the options.
length(providers)
#> [1] 164
names(providers) %>%
head()
#> [1] "OpenStreetMap" "OpenStreetMap.Mapnik"
#> [3] "OpenStreetMap.DE" "OpenStreetMap.CH"
#> [5] "OpenStreetMap.France" "OpenStreetMap.HOT"
Note that some tile set providers require you to register. You can pass access tokens/keys, and other options, to the tile provider by populating the options argument with the providerTileOptions() function.
Below are a few examples:
leaflet() %>%
setView(lng=-119.8489, lat=34.4140, zoom = 12) %>%
addProviderTiles(providers$CartoDB)
leaflet() %>%
setView(lng=-119.8489, lat=34.4140, zoom = 12) %>%
addProviderTiles(providers$Stamen.Toner)
leaflet() %>%
setView(lng=-119.8489, lat=34.4140, zoom = 12) %>%
addProviderTiles(providers$Esri.WorldImagery)
leaflet() %>%
setView(lng=-119.8489, lat=34.4140, zoom = 12) %>%
addProviderTiles(providers$Stamen.TopOSMRelief)
You can stack multiple tile layers if the front tiles have some level of opacity. Here we layer the Stamen.TonerLines with aerial imagery
leaflet() %>%
setView(lng=-119.8489, lat=34.4140, zoom = 12) %>%
addProviderTiles(providers$Esri.WorldImagery) %>%
addProviderTiles(providers$Stamen.TonerLines, options = providerTileOptions(opacity = .5))
Markers are one way to identify point information on a map:
(starbucks = read_csv('data/directory.csv') %>%
filter(City %in% c("Goleta", "Santa Barbara")) %>%
st_as_sf(coords = c("Longitude", "Latitude"), crs = 4326) %>%
select(store_name = `Store Name`, phone = `Phone Number`, address = `Street Address`, city = City, brand = Brand))
#> Simple feature collection with 11 features and 5 fields
#> geometry type: POINT
#> dimension: XY
#> bbox: xmin: -119.87 ymin: 34.4 xmax: -119.65 ymax: 34.44
#> geographic CRS: WGS 84
#> # A tibble: 11 x 6
#> store_name phone address city brand geometry
#> <chr> <chr> <chr> <chr> <chr> <POINT [°]>
#> 1 Hollister … 805-9… 7030 Mar… Gole… Star… (-119.87 34.43)
#> 2 Goleta 805-6… 173 N. F… Gole… Star… (-119.83 34.44)
#> 3 Montecito (805)… 1046 - A… Sant… Star… (-119.65 34.42)
#> 4 State & Co… 805-8… 539 Stat… Sant… Star… (-119.7 34.42)
#> 5 Ralph's - … 805-5… 100 W Ca… Sant… Star… (-119.7 34.42)
#> 6 800 State … (805)… 800 Stat… Sant… Star… (-119.7 34.42)
#> 7 W Carrillo… 805-8… 208 West… Sant… Star… (-119.7 34.42)
#> 8 La Cumbre … 805-5… 3815 Sta… Sant… Star… (-119.75 34.44)
#> 9 Five Point… (805)… 3957 Sta… Sant… Star… (-119.75 34.44)
#> 10 State & Vi… 805-8… 1235 Sta… Sant… Star… (-119.71 34.42)
#> 11 1990 Cliff… 805-8… 1990 Cli… Sant… Star… (-119.72 34.4)
Markers are added using the addMarkers
or addAwesomeMarkers
Their default appearance is a blue dropped pin.
As with most layer functions, - the popup
argument adds a message to be displayed on click - the label
argument display a text label either on hover
leaflet() %>%
addProviderTiles(providers$CartoDB) %>%
addMarkers(data = starbucks, popup = ~store_name, label = ~city)
Using the Font Awesome Icons seen in lab one, we can make markers with more specific coloring and icons
We then use addAwesomeMarkers to spcifiy the icon we created using the icon argument:
icons = awesomeIcons(icon = 'coffee', markerColor = "green", library = 'fa', spin = TRUE)
leaflet(data = starbucks) %>% addProviderTiles(providers$CartoDB) %>%
addAwesomeMarkers(icon = icons, popup = ~store_name)
You can use HTML, CSS, and Java Script to modify your pop-ups
For example, we can associate the name of the Starbucks locations with their google maps URL as an hyper reference (href):
starbucks = starbucks %>%
mutate(url = paste0('https://www.google.com/maps/place/',
gsub(" ", "+", address), "+",
gsub(" ", "+", city)))
pop = paste0('<a href=', starbucks$url, '>', starbucks$store_name, "</a>")
head(pop)
#> [1] "<a href=https://www.google.com/maps/place/7030+Marketplace+Drive+Goleta>Hollister & Storke-Goleta</a>"
#> [2] "<a href=https://www.google.com/maps/place/173+N.+Fairview+Avenue+Goleta>Goleta</a>"
#> [3] "<a href=https://www.google.com/maps/place/1046+-+A+Coast+Village+Road,+Paseo+Nuevo+Shops+Santa+Barbara>Montecito</a>"
#> [4] "<a href=https://www.google.com/maps/place/539+State+Street+Santa+Barbara>State & Cota, Santa Barbara</a>"
#> [5] "<a href=https://www.google.com/maps/place/100+W+Carrillo+St+Santa+Barbara>Ralph's - Santa Barbara #680</a>"
#> [6] "<a href=https://www.google.com/maps/place/800+State+Street+Santa+Barbara>800 State Street</a>"
We can then add our custom popup to our icons:
leaflet(data = starbucks) %>%
addProviderTiles(providers$CartoDB) %>%
addAwesomeMarkers(icon = icons,
label = ~address, popup = pop)
Circle markers are much like regular circles (shapes), except their radius in onscreen pixels stays constant regardless of zoom level (z).
leaflet(data = starbucks) %>%
addProviderTiles(providers$CartoDB) %>%
addCircleMarkers(label = ~address, popup = pop)
Sometimes while mapping many points, it is useful to cluster them. For example lets plot all starbucks in the world!
all_sb = read_csv('data/directory.csv') %>%
filter(!is.na(Latitude)) %>%
st_as_sf(coords = c("Longitude", "Latitude"), crs = 4326)
leaflet(data = all_sb) %>%
addProviderTiles(providers$CartoDB) %>%
addMarkers(clusterOptions = markerClusterOptions())
The palette argument can be any of the following:
The domain is the values - named by variable - that the color palette should range over
# ?colorFactor
# Create a palette that maps factor levels to colors
pal <- colorFactor(c("darkgreen", "navy"), domain = c("Goleta", "Santa Barbara"))
leaflet(data = starbucks) %>% addProviderTiles(providers$CartoDB) %>%
addCircleMarkers(color = ~pal(city), fillOpacity = .5, stroke = FALSE)
(covid = readr::read_csv('https://raw.githubusercontent.com/nytimes/covid-19-data/master/live/us-states.csv') %>%
filter(date == max(date)) %>%
right_join(USAboundaries::us_states(), by = c("state" = "name")) %>%
filter(!stusps %in% c("AK","PR", "HI")) %>%
st_as_sf())
#> Simple feature collection with 49 features and 20 fields
#> geometry type: MULTIPOLYGON
#> dimension: XY
#> bbox: xmin: -124.7258 ymin: 24.49813 xmax: -66.9499 ymax: 49.38436
#> geographic CRS: WGS 84
#> # A tibble: 49 x 21
#> date state fips cases deaths confirmed_cases
#> <date> <chr> <chr> <dbl> <dbl> <dbl>
#> 1 2021-03-17 Alabama 01 5.09e5 10337 396375
#> 2 2021-03-17 Arizona 04 8.34e5 16574 NA
#> 3 2021-03-17 Arkansas 05 3.27e5 5493 257449
#> 4 2021-03-17 California 06 3.63e6 56719 3606156
#> 5 2021-03-17 Colorado 08 4.47e5 6129 NA
#> 6 2021-03-17 Connecticut 09 2.94e5 7799 NA
#> 7 2021-03-17 Delaware 10 9.08e4 1514 NA
#> 8 2021-03-17 District of Colum… 11 4.27e4 1042 42730
#> 9 2021-03-17 Florida 12 1.98e6 32448 0
#> 10 2021-03-17 Georgia 13 1.01e6 17735 812675
#> # … with 39 more rows, and 15 more variables:
#> # confirmed_deaths <dbl>, probable_cases <dbl>,
#> # probable_deaths <dbl>, statefp <chr>, statens <chr>,
#> # affgeoid <chr>, geoid <chr>, stusps <chr>, lsad <chr>,
#> # aland <dbl>, awater <dbl>, state_name <chr>, state_abbr <chr>,
#> # jurisdiction_type <chr>, geometry <MULTIPOLYGON [°]>
Adding those cases counts to polygons over a YlOrRd
color ramp
leaflet() %>%
addProviderTiles(providers$CartoDB) %>%
addPolygons(data = covid,
fillColor = ~colorQuantile("YlOrRd", confirmed_cases)(confirmed_cases),
color = NA,
label = ~state_name)
leaflet() %>%
addProviderTiles(providers$CartoDB.DarkMatter) %>%
addCircles(data = st_centroid(covid),
fillColor = ~colorQuantile("YlOrRd", cases)(cases),
color = NA,
fillOpacity = .5,
radius = ~cases/3,
label = ~cases)
https://labs.waterdata.usgs.gov/api/nldi/linked-data/nwissite/USGS-11120000/navigate/UT
Trance the Upper Tributary (UT) of the USGS-11120000
# site ID
id = "11120000"
# base URL
base ="https://labs.waterdata.usgs.gov/api/nldi/linked-data/"
# Reading sf for URLs in line
leaflet() %>%
addProviderTiles(providers$CartoDB) %>%
addPolylines(data = read_sf(paste0(base,'nwissite/USGS-',id,'/navigate/UT'))) %>%
addPolygons(data = read_sf(paste0(base,'nwissite/USGS-',id,'/basin')),
fillColor = "transparent", color = "black")
WMS tiles can be added directly to a map. Here we use the NEXRAD rainfall information (refelctivity) from the Iowa Mesonet Program
(You may need to scroll out to find an)
conus = filter(us_states(), !stusps %in% c("AK", "PR", "HI"))
leaflet() %>%
addProviderTiles(providers$CartoDB) %>%
addPolygons(data = st_union(conus), fillColor = "transparent",
color = "black", weight = 1) %>%
addWMSTiles(
"http://mesonet.agron.iastate.edu/cgi-bin/wms/nexrad/n0r.cgi",
layers = "nexrad-n0r-900913",
options = WMSTileOptions(format = "image/png", transparent = TRUE)
)
Uses Leaflet’s built-in layers control you can choose one of several base layers, and any number of overlay layers to view.
By defining groups, you have the ability to toogle layers, and overlays on/off.
leaflet() %>%
addProviderTiles(providers$CartoDB, group = "Grayscale") %>%
addProviderTiles(providers$Esri.WorldTerrain, group = "Terrain") %>%
addPolylines(data = read_sf(paste0(base,'nwissite/USGS-',id,'/navigate/UT'))) %>%
addPolygons(data = read_sf(paste0(base,'nwissite/USGS-',id,'/basin')), fillColor = "transparent", color = "black", group = "basin") %>%
addWMSTiles("http://mesonet.agron.iastate.edu/cgi-bin/wms/nexrad/n0r.cgi", layers = "nexrad-n0r-900913",
options = WMSTileOptions(format = "image/png", transparent = TRUE)) %>%
addLayersControl(overlayGroups = c("basin"), baseGroups = c("Terrain", "Grayscale"))
You can wrap your mapping code in functions to allow reusability
watershed_map = function(gage_id){
leaflet() %>%
addProviderTiles(providers$CartoDB) %>%
addPolylines(data = read_sf(paste0(base,'nwissite/USGS-',gage_id,'/navigate/UT'))) %>%
addPolygons(data = read_sf(paste0(base,'nwissite/USGS-',gage_id,'/basin')),
fillColor = "transparent", color = "black", group = "basin") %>%
addWMSTiles("http://mesonet.agron.iastate.edu/cgi-bin/wms/nexrad/n0r.cgi", layers = "nexrad-n0r-900913",
options = WMSTileOptions(format = "image/png", transparent = TRUE))
}
watershed_map("07382000")
watershed_map("07382000") %>%
addMeasure() %>%
addGraticule() %>%
addMiniMap()
watershed_map("07382000") %>%
addMeasure() %>%
addGraticule() %>%
leafem::addHomeButton(group = "basin") %>%
leafem::addMouseCoordinates()
leaflet(data = starbucks) %>%
addProviderTiles(providers$CartoDB) %>%
addCircleMarkers(
color = ~pal(city),
fillOpacity = .5,
stroke = FALSE,
popup = leafpop::popupTable(starbucks)
)
Making that table nicer…
leaflet(data = starbucks) %>% addProviderTiles(providers$CartoDB) %>%
addCircleMarkers(
color = ~pal(city), fillOpacity = .5,
stroke = FALSE,
popup = leafpop::popupTable(st_drop_geometry(starbucks[,1:5]), feature.id = FALSE, row.numbers = FALSE)
)
leafem
and leafpop
functionalitieslibrary(mapview)
mapview(starbucks)