Welcome! While we’re waiting:
Please download the workshop files from: https://github.com/dlab-geo/r-leaflet-workshop
Unzip the Zipfile: https://github.com/dlab-geo/r-leaflet-workshop/archive/master.zip
Open RStudio
Open a new R script file
Introductions
Leaflet is a lightweight, yet powerful javascript library for creating interactive web maps.
Leaflet maps are a combination of HTML and Javascript code that is meant to be rendered in a web browser.
You can use the R leaflet package to create Leaflet maps in R without knowing HTML and Javascript!
leaflet
R package to make a custom, interactive map of your data.html
file.leaflet
?There are a number of R packages for making Leaflet maps.
leaflet is actively maintained, highly customizable, and integrates well with other R libraries.
Geospatial Data in R
workshop series.Download workshop files: https://github.com/dlab-geo/r-leaflet-workshop
Follow along:
Make sure you can copy and paste from one of the above into the script.
Load the packages we will use today
library(leaflet)
library(RColorBrewer)
library(sp)
library(rgdal)
library(htmlwidgets)
library(dplyr)
Install any packages that you do not have on your computer
to the folder in which you unzipped the workshop files
map1 <- leaflet() # Initialize the leaflet map object
map1 <- addTiles(map1) # Add basemap - default is OpenStreetMap
map1 # Display the map
WARNING don’t call your map object map
map1 <- leaflet() # Initialize the leaflet map object
map1 <- addTiles(map1) # Add basemap - default is OpenStreetMap
map1 # Display the map
Its very common use piping
or chaining
syntax….
The output of one command becomes the input of the next command.
map1 <- leaflet() %>% # Initialize the leaflet map object
addTiles() # Add basemap - default is OpenStreetMap
map1 # Display the map
Use setView to specify the center
of the map and the initial zoom
level.
map1 <- leaflet() %>%
addTiles() %>%
setView(lat=37.87004, lng=-122.25817, zoom = 15)
map1
map1 # setView(lat=37.87004, lng=-122.25817, zoom = 15)
Create a leaflet map centered on San Francisco with an intial zoom level of 14.
Questions
What zoom level shows all of the city without much more?
What is the max possible zoom level?
The maximum zoom level is 18
leaflet() %>%
addTiles() %>%
setView(lat=37.76175, lng=-122.4470, zoom = 12)
How does this code limit the map?
map1 <- leaflet(options=leafletOptions(minZoom=15, maxZoom=18)) %>%
addTiles() %>%
setView(lat=37.87004, lng=-122.25817, zoom = 16) %>%
setMaxBounds(-122.2570, 37.866458, -122.2553,37.877167)
map1
By default, Leaflet uses the OpenStreetMap basemap, which is added with the addTiles()
function
leaflet() %>% addTiles() %>%
setView(lat=37.870, lng=-122.258, zoom = 15)
Use addProviderTiles
with the name of the basemap
to add a different basemap.
Create a leaflet map with the ESRI World Street Map
basemap.
map2 <- leaflet() %>%
addProviderTiles("Esri.WorldStreetMap") %>%
setView(lat=37.870044, lng=-122.258169, zoom = 12)
map2 #Using ESRI WorldStreetMap basemap
Add a different basemap by taking a look at this web page of available basemaps
http://leaflet-extras.github.io/leaflet-providers/preview/
Use the provider name
in quotes to access the basemap.
leaflet() %>% addProviderTiles("CartoDB.Positron") %>%
setView(lat=37.870044, lng=-122.258169, zoom = 12)
For more info, read the documentation
?addProviderTiles
Barrows Hall, longitude=-122.25817, latitude=37.87004
Use addMarkers
to add one or more data points to the map.
map3 <- leaflet() %>%
addTiles() %>%
addMarkers(lat=37.87004, lng=-122.25817, popup="Barrows Hall")
map3
Markers show location and a little information
map3 <- leaflet() %>%
addTiles() %>%
#setView(lat=37.870044, lng=-122.258169, zoom = 17) %>%
addMarkers(lat=37.87004, lng=-122.25817, popup="Barrows Hall")
map3
You don’t need to use setView
(commented out).
The map will automatically center on the marker data and determine the zoom level.
But, you can override this with setView
.
What does popup=
do?
You can always check the function documentation to see your options!
?addMarkers
How would you add a second marker for Cafe Milano?
37.868641, -122.258537
Try it?
map3 <- leaflet() %>%
addTiles() %>%
addMarkers(lat=37.87004, lng=-122.25817, popup="Barrows Hall") %>%
addMarkers(lat=37.86850, lng=-122.25830, popup="Cafe Milano")
map3
map3 <- leaflet() %>%
addTiles() %>%
addMarkers(lat = c(37.87004,37.86850),
lng = c(-122.25817,-122.25830),
popup = c("Go Bears", "Cafe Milano"))
map3
Source: Caltrans GIS Data
bart <- read.csv('data/bart.csv', stringsAsFactors = FALSE)
str(bart)
## 'data.frame': 44 obs. of 6 variables:
## $ X : num -122 -122 -122 -122 -122 ...
## $ Y : num 37.9 37.9 37.9 37.8 37.8 ...
## $ STATION : chr "NORTH BERKELEY" "DOWNTOWN BERKELEY" "ASHBY" "ROCKRIDGE" ...
## $ OPERATOR: chr "BART" "BART" "BART" "BART" ...
## $ DIST : int 4 4 4 4 4 4 4 4 4 4 ...
## $ CO : chr "ALA" "ALA" "ALA" "ALA" ...
What column(s) contain the geographic data?
map4 <- leaflet() %>%
addTiles() %>%
addMarkers(lat=bart$Y, lng=bart$X,
popup= paste("Station:", bart$STATION))
map4
map4
Point data are often stored in CSV
files and loaded into R data frames.
These point data are manipulated like other R data frames.
Leaflet can map these data if the points use geographic coordinates (longitude & latitude).
More complex geographic data are commonly stored in ESRI Shapefiles
.
To get the most out of spatial data in R you should use packages specifically for working with spatial data.
We can use the sp
and rgdal
packages to import, manipulate and map more complex spatial objects.
sp
- R classes and methods for spatial data
rgdal
- Functions for importing and transforming spatial data
Let’s use these to import data in ESRI Shapefiles
BART Lines
Source: Caltrans GIS Data
dir("data/BART_13/")
## [1] "BART_13.dbf" "BART_13.prj" "BART_13.sbn" "BART_13.sbx"
## [5] "BART_13.shp" "BART_13.shp.xml" "BART_13.shx"
Use rgdal
to read in the data from a Shapefile
library(rgdal)
bart_lines <- readOGR(dsn="data/BART_13",layer="BART_13")
## OGR data source with driver: ESRI Shapefile
## Source: "data/BART_13", layer: "BART_13"
## with 6 features
## It has 3 fields
Take a look at the data
summary(bart_lines)
## Object of class SpatialLinesDataFrame
## Coordinates:
## min max
## x -122.47113 -121.89932
## y 37.55675 38.02386
## Is projected: FALSE
## proj4string :
## [+proj=longlat +datum=NAD83 +no_defs +ellps=GRS80 +towgs84=0,0,0]
## Data attributes:
## ROUTE Shape_Leng LINE
## Dublin/Pleasanton to Daly City :1 Min. : 3686 Blue :1
## Fremont to Daly City :1 1st Qu.:62836 Green :1
## Fremont to Richmond :1 Median :64169 Orange:1
## Millbrae to SFO Shuttle :1 Mean :58883 Red :1
## Pittsburg/Bay Point to SFO to Millbrae:1 3rd Qu.:64962 Yellow:1
## Richmond to Daly City to Millbrae :1 Max. :93658 NA's :1
Use addPolyLines
to add linear features
map4 <- leaflet() %>%
addTiles() %>%
addMarkers(lat=bart$Y, lng=bart$X,
popup= paste("Station:", bart$STATION)) %>%
addPolylines(data=bart_lines, color="black", weight=3)
map4
Leaflet can map both data frames & spatial objects!
map4
Let’s add BART Service Area data, a subset from the Metropolitan Transportation Commission (MTC) Transit Service Area data.
dir("data/Transit_Service_Areas_2016")
## [1] "bart_service_area.dbf" "bart_service_area.prj"
## [3] "bart_service_area.qpj" "bart_service_area.shp"
## [5] "bart_service_area.shx" "Transit_Service_Areas_2016.cpg"
## [7] "Transit_Service_Areas_2016.dbf" "Transit_Service_Areas_2016.prj"
## [9] "Transit_Service_Areas_2016.shp" "Transit_Service_Areas_2016.shx"
## [11] "Transit_Service_Areas_2016.xml"
Let’s add BART Service Area data from the Metropolitan Transportation Commission (MTC)
bart_service <- readOGR(dsn="data/Transit_Service_Areas_2016",layer="bart_service_area")
## OGR data source with driver: ESRI Shapefile
## Source: "data/Transit_Service_Areas_2016", layer: "bart_service_area"
## with 3 features
## It has 7 fields
## Integer64 fields read as strings: OBJECTID
Take a look at the data
summary(bart_service)
## Object of class SpatialPolygonsDataFrame
## Coordinates:
## min max
## x -122.47784 -121.77617
## y 37.32445 38.02598
## Is projected: FALSE
## proj4string :
## [+proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0]
## Data attributes:
## OBJECTID agency_id agency_nam status system
## 13:1 BA:3 BART:3 Existing :1 Rail:3
## 14:1 Planned :1
## 15:1 Under Construction:1
##
##
##
## Shape__Are Shape__Len
## Min. : 9885713 Min. : 22981
## 1st Qu.:10027470 1st Qu.: 24130
## Median :10169227 Median : 25279
## Mean :35531127 Mean : 84825
## 3rd Qu.:48353833 3rd Qu.:115747
## Max. :86538439 Max. :206215
Use addPolygons
to add area features
map4 <- leaflet() %>%
setView(lat=37.857900, lng=-122.245156, zoom = 12) %>%
addTiles() %>%
addMarkers(lat=bart$Y, lng=bart$X,
popup= paste("Station:", bart$STATION)) %>%
addPolylines(data=bart_lines, color="black", weight=4) %>%
addPolygons(data=bart_service, color="blue", opacity = 0.6)
map4
map4
Redo the previous map and:
change the basemap to “CartoDB.Positron”
set the default view to center on San Francisco
map4 <- leaflet() %>%
setView(lat=37.76175, lng=-122.4470, zoom = 12) %>%
addProviderTiles("CartoDB.Positron") %>%
addMarkers(lat=bart$Y, lng=bart$X,
popup= paste("Station:", bart$STATION)) %>%
addPolylines(data=bart_lines, color="black", weight=4) %>%
addPolygons(data=bart_service, color="blue", opacity = 0.6)
map4
All geospatial data are referenced to a coordinate reference system
, or CRS
.
projection
or map projection
A discussion of CRSs
is beyond the scope of this workshop!
Geospatial Data in R
workshop series to learn more.CRSs and R Leaflet
Leaflet package expects data to be specified in latitude and longitude coordinates and assumes the using WGS 84 (a.k.a. EPSG:4326) CRS.
See the Leaflet for R tutorial for more information.
Save the map as an HTML file that you can then open in a browser, share with friends, put online.
You will need to have the htmlwidgets
package installed and loaded to save to HTML.
#library(htmlwidgets)
saveWidget(map4, file="bartmap.html")
San Francisco Open Data Portal
This data set includes the Office of the Assessor-Recorder’s secured property tax roll spanning from 2015.
We are using this as a proxy for home values.
We are working with a simplified version of the full data set.
Set your working directory first to the folder where you downloaded the workshop files!
sfhomes <- read.csv('data/sfhomes15.csv', stringsAsFactors = FALSE)
str(sfhomes)
## 'data.frame': 680 obs. of 11 variables:
## $ SalesDate : chr "2015-08-21" "2015-08-13" "2015-12-29" "2015-07-06" ...
## $ Address : chr "0000 2760 19TH AV0015" "0000 0560AMISSOURI ST0000" "0000 0718 LONG BRIDGE ST1202" "0000 0899 VALENCIA ST0202" ...
## $ YrBuilt : int 1979 2003 2016 2015 1961 1900 2015 NA 1947 1907 ...
## $ NumBeds : int 2 2 2 3 3 2 2 0 0 3 ...
## $ NumBaths : int 2 2 2 3 3 2 2 0 0 3 ...
## $ NumUnits : int 1 1 1 1 1 1 1 1 1 1 ...
## $ AreaSqFt : int 1595 1191 1346 1266 1840 1256 1520 536 950 1837 ...
## $ Neighborhood: chr "Twin Peaks" "Potrero Hill" "Mission Bay" "Mission" ...
## $ Value : int 865000 1402560 2260993 1700000 2309692 2700564 1925000 583768 944180 1750001 ...
## $ lat : num 37.7 37.8 37.8 37.8 37.8 ...
## $ lon : num -122 -122 -122 -122 -122 ...
head(sfhomes)
## SalesDate Address YrBuilt NumBeds NumBaths
## 1 2015-08-21 0000 2760 19TH AV0015 1979 2 2
## 2 2015-08-13 0000 0560AMISSOURI ST0000 2003 2 2
## 3 2015-12-29 0000 0718 LONG BRIDGE ST1202 2016 2 2
## 4 2015-07-06 0000 0899 VALENCIA ST0202 2015 3 3
## 5 2015-06-12 0000 1333 JONES ST0808 1961 3 3
## 6 2015-04-14 0000 1904 BAKER ST0000 1900 2 2
## NumUnits AreaSqFt Neighborhood Value lat lon
## 1 1 1595 Twin Peaks 865000 37.73601 -122.4741
## 2 1 1191 Potrero Hill 1402560 37.75920 -122.3965
## 3 1 1346 Mission Bay 2260993 37.77181 -122.3942
## 4 1 1266 Mission 1700000 37.75876 -122.4210
## 5 1 1840 Nob Hill 2309692 37.79362 -122.4149
## 6 1 1256 Pacific Heights 2700564 37.78881 -122.4437
map4 <- leaflet() %>%
addTiles() %>%
addMarkers(lat=sfhomes$lat, lng=sfhomes$lon,
popup= paste("Address:", sfhomes$Address,
"<br>", # add line break
"Property Value: ", sfhomes$Value))
map4
We can add to and save the popup code and re-use it instead of typing it over and over again.
popup_content <- paste("<b>Address:</b>", sfhomes$Address,"<br>",
"<b>Property Value</b>: ", sfhomes$Value, "<br>",
"<b>Neighborhood:</b> ", sfhomes$Neighborhood, "<br>",
"<b>Num Bedrooms: </b>", sfhomes$NumBeds, "<br>",
"<b>Num Bathrooms:</b>", sfhomes$NumBaths
)
map4 <- leaflet() %>%
addTiles() %>%
addMarkers(lat=sfhomes$lat, lng=sfhomes$lon,
popup= popup_content)
map4
Instead of this:
leaflet() %>%
addTiles() %>%
addMarkers(lat=sfhomes$lat, lng=sfhomes$lon, popup= popup_content)
We can use this syntax:
leaflet(sfhomes) %>%
addTiles() %>%
addMarkers(~lon, ~lat, popup = popup_content)
When the addMarkers function arguments lng=
and lat=
are not named they must be in the expected order (longitude, latitude)!
Read the addMarker
documentation for options to address this.
addMarkers(map, lng = NULL, lat = NULL, layerId = NULL,
group = NULL, icon = NULL, popup = NULL,
options = markerOptions(),
clusterOptions = NULL, clusterId = NULL,
data = getMapData(map))
map4 <- leaflet(sfhomes) %>%
addTiles() %>%
addMarkers(~lon, ~lat, popup= popup_content,
clusterOptions = 1)
map4 # Explore the Map - hover over a cluster marker, zoom in.
addCircleMarker
map4 <- leaflet(sfhomes) %>%
addTiles() %>%
addCircleMarkers(~lon, ~lat, popup = popup_content)
addCircleMarker
map4
addCircleMarkers(map, lng = NULL, lat = NULL, radius = 10,
layerId = NULL, group = NULL, stroke = TRUE, color = "#03F",
weight = 5, opacity = 0.5,
fill = TRUE, fillColor = color, ....)
Change color, radius and stroke weight of circle markers
map4 <- leaflet(sfhomes) %>%
addTiles() %>%
addCircleMarkers(~lon, ~lat, popup = popup_content,
color="white", radius=6, weight=2, # stroke
fillColor="red",fillOpacity = 0.75 # fill
)
colors()
to see a list of all R named colors.map4
Can you cluster circleMarkers
?
Basic leaflet map with a basemap
Mapping point locations with Markers
Mapping linear features with addPolylines
Mapping polygon (or area) features with addPolygons
Clustering lots of point features
Reading in data from CSV and Spatial Data Files
Working with Popups
Not just interested in location
Interested in how data values vary by location
Use data values to determine the size
and color
of symbols.
We can map points & lines by making their size a function of a data value.
Earthquakes by Magnitude, 1989 - 2019
quake_url <-"http://earthquake.usgs.gov/fdsnws/event/1/query?format=csv&minmagnitude=3.5"
startdate <- "1989-01-01"
enddate <- "2019-01-31"
#
bayminlat <- 36.433
baymaxlat <- 38.694
bayminlon <- -123.865
baymaxlon <- -120.951
quake_url <- paste0(quake_url, "&starttime=", startdate, "&endtime=", enddate,
"&minlatitude=",bayminlat, "&maxlatitude=", baymaxlat,
"&minlongitude=", bayminlon,"&maxlongitude=",baymaxlon)
quakes <- read.csv(quake_url)
#print(quake_url)
Set the radius of the circle to be a function of the magnitude of the earthquake.
quake_map <- leaflet(quakes) %>%
addProviderTiles("Esri.WorldTopoMap") %>%
addCircleMarkers(~longitude, ~latitude,
popup=paste0("Magnitude: ", quakes$mag, "<br>Date: ", quakes$time),
fillColor= "Red", color="Red", weight=1, fillOpacity = 0.25,
radius= 1.75^quakes$mag #exponential
)
With addCircleMarkers
the radii are pixels so they adjust dynamically with the map.
With addCircle
radii are specified absolutely in meters
quake_map <- leaflet(quakes) %>%
addProviderTiles("Esri.WorldTopoMap") %>%
addCircles(~longitude, ~latitude,
fillColor= "Red", color="black", weight=1, fillOpacity = 0.25,
popup=paste0("Magnitude: ", quakes$mag, "<br>Date: ", quakes$time),
radius= 5000 # 5 kilometer neighborhood
)
Use addCircle
when you want to map specific not relative size.
5 KM radius around earthquake epicenters
quake_map <- leaflet(quakes) %>%
addProviderTiles("Esri.WorldTopoMap") %>%
addCircles(~longitude, ~latitude,
color="black", fillColor= "Red", weight=1, fillOpacity = 0.25,
radius= 5000 # 5 kilometer neighborhood
) %>%
addCircleMarkers(~longitude, ~latitude,
popup=paste0("Magnitude: ", quakes$mag, "<br>Date: ", quakes$time),
color="black", fillColor="black",fillOpacity=1,
radius=4
)
Data values & Color palettes
Data Binning & Classification methods
|
|
emphasize different categories with contrasting colors
display.brewer.all(type="qual")
display.brewer.pal(7, "Set3" ) # Try a different number of colors
highlight trends in numerical data
display.brewer.all(type="seq")
highlight outliers
display.brewer.all(type="div")
Let’s map sfhomes
by the values in the Neighborhood
column.
First, check out the RColorBrewer qualitative color palettes
display.brewer.all(type="qual")
colorfactor
takes as input a color palette and a domain that contains the full range of possible values to be mapped.
colorfactor
returns a function specific to that domain that can be used to output a set of color values.
# Create a qualitative color palette
myColor_function <- colorFactor("Paired", sfhomes$Neighborhood)
myCategoryColor_function <- colorFactor("Paired", sfhomes$Neighborhood)
category_map <- leaflet(sfhomes) %>%
addProviderTiles("CartoDB.Positron") %>%
addCircleMarkers(~lon, ~lat,
popup= popup_content,
fillColor= ~myCategoryColor_function(Neighborhood),
radius=6, color=NA, weight=2, fillOpacity = 1
)
category_map # what neighborhood had the most 2015 transactions?
myCategoryColor_function <- colorFactor("Paired", sfhomes$Neighborhood)
category_map <- leaflet(sfhomes) %>%
addProviderTiles("CartoDB.Positron") %>%
addCircleMarkers(~lon, ~lat, popup=popup_content,
fillColor= ~myCategoryColor_function(Neighborhood),
radius=6, color=NA, weight=2,fillOpacity = 1
) %>%
addLegend(title = "Neighborhood",
pal = myCategoryColor_function,
values = ~Neighborhood, opacity = 1,
position="bottomleft")
category_map
Recreate the categorical
map of SF homes by neigborhood using a different color palette:
display.brewer.all(type="qual")
Be sure to add a legend
Let’s map the homes by property value.
First, check out the sequential color palettes
display.brewer.all(type="seq")
To map data values to a continuous range of colors use colorNumeric
.
First, create the color mapping function
myNumericColor_function <- colorNumeric("Reds", sfhomes$Value)
Use the numColor_function
to create a continuous color map
myNumericColor_function <- colorNumeric("Reds", sfhomes$Value)
numeric_map <- leaflet(sfhomes) %>%
addProviderTiles("CartoDB.Positron") %>%
addCircleMarkers(~lon, ~lat, popup=popup_content,
fillColor= ~myNumericColor_function(Value),
radius=6, color="grey", weight=1, fillOpacity = 1
) %>%
addLegend(title = "Property Values",
pal = myNumericColor_function,
values = ~Value, opacity = 1,
position="bottomleft")
numeric_map # continuous color map
Recreate the continuous
map of SF homes by property using a different color palette:
display.brewer.all(type="seq")
Be sure to add the legend
Use colorQuantile
to create a color palette based on quantile binning of the data.
First, create the color mapping function
myQuantileColor_function <- colorQuantile("Reds", sfhomes$Value, n=5)
Use the color function to map colors to house values
myQuantileColor_function <- colorQuantile("Reds", sfhomes$Value, n=5)
quantile_map <- leaflet(sfhomes) %>%
addProviderTiles("CartoDB.Positron") %>%
addCircleMarkers(~lon, ~lat, popup=popup_content,
fillColor= ~myQuantileColor_function(Value),
radius=6, color="grey", weight=1,fillOpacity = 1
) %>%
addLegend(title = "Property Values, 2015",
pal = myQuantileColor_function,
values = ~Value, opacity = 1,
position="bottomleft")
quantile_map # Graduated quantile color map
myQuantileColor_function <- colorQuantile("Reds", sfhomes$Value, n=5)
quantile_map2 <- leaflet(sfhomes) %>%
addProviderTiles("CartoDB.Positron") %>%
addCircleMarkers(~lon, ~lat, popup=popup_content,
fillColor= ~myQuantileColor_function(Value),
radius=6, color="grey", weight=1,fillOpacity = 1) %>%
addLegend(pal = myQuantileColor_function, values = ~Value,
title = "Property Values, 2015",
position="bottomleft",
opacity=1,
labFormat = function(type, cuts, p) {
n = length(cuts)
cuts = paste0("$", format(cuts[-n], big.mark=","),
" - ", "$",format(cuts[-1], big.mark=","))
}
)
with custom legend
quantile_map2
Recreate the quantile
map of SF homes by property using a different color palette. Be sure to add a custom legend.
Select your palette from one of the following from the Viridis
package:
myQuantileColor_function <- colorQuantile("inferno", sfhomes$Value, n=5, reverse=T)
quantile_map3 <- leaflet(sfhomes) %>%
addProviderTiles("CartoDB.Positron") %>%
addCircleMarkers(~lon, ~lat, popup=popup_content,
fillColor= ~myQuantileColor_function(Value),
radius=6, color="grey", weight=1,fillOpacity = 1) %>%
addLegend(pal = myQuantileColor_function, values = ~Value,
title = "Property Values, 2015",
position="bottomleft",
opacity=1,
labFormat = function(type, cuts, p) {
n = length(cuts)
cuts = paste0("$", format(cuts[-n], big.mark=","),
" - ", "$",format(cuts[-1], big.mark=","))
}
)
Inferno Color Palette
For more control over customizing colors see the colorBin
function which can be used to create color palettes based on different classification methods for binning the data, eg equal interval, natural breaks etc.
?colorBin
Basic Maps
addMarkers
- Simple Marker MapsaddCircleMarkers
- Circle Marker MapsData Maps
addCircles
Proportional symbol mapscolorFactor
- Category MapscolorNumeric
- Continuous color mapscolorQuantile
- Graduated color mapsSan Francisco Median Household Income, 2016
Color areas based on data values.
The most common type of data map.
The data values are classified into bins.
Quantile classification is the default.
Each bin gets a unique color from a color palette.
sf_md_hhi <- readOGR(dsn="data",layer="sf_medhhincome_acs5y_16")
## OGR data source with driver: ESRI Shapefile
## Source: "data", layer: "sf_medhhincome_acs5y_16"
## with 196 features
## It has 5 fields
summary(sf_md_hhi)
## Object of class SpatialPolygonsDataFrame
## Coordinates:
## min max
## x -123.01392 -122.32756
## y 37.69274 37.86334
## Is projected: FALSE
## proj4string :
## [+proj=longlat +datum=NAD83 +no_defs +ellps=GRS80 +towgs84=0,0,0]
## Data attributes:
## GEOID
## 06075010100: 1
## 06075010200: 1
## 06075010300: 1
## 06075010400: 1
## 06075010500: 1
## 06075010600: 1
## (Other) :190
## NAME variable
## Census Tract 101, San Francisco County, California: 1 B19013_001:196
## Census Tract 102, San Francisco County, California: 1
## Census Tract 103, San Francisco County, California: 1
## Census Tract 104, San Francisco County, California: 1
## Census Tract 105, San Francisco County, California: 1
## Census Tract 106, San Francisco County, California: 1
## (Other) :190
## estimate moe
## Min. : 11971 Min. : 739
## 1st Qu.: 65893 1st Qu.: 9744
## Median : 89668 Median :15343
## Mean : 91151 Mean :16211
## 3rd Qu.:117922 3rd Qu.:20032
## Max. :205865 Max. :89454
## NA's :2 NA's :2
Map sf_md_hhi
with addPolygons
poly_map <- leaflet() %>%
addTiles() %>%
addPolygons(data=sf_md_hhi)
poly_map # using addPolygons to map sf_md_hhi
?addPolygons
addPolygons(map, lng = NULL, lat = NULL, layerId = NULL, group = NULL,
stroke = TRUE, color = "#03F", weight = 5, opacity = 0.5,
fill = TRUE, fillColor = color, fillOpacity = 0.2,
dashArray = NULL, smoothFactor = 1, noClip = FALSE,
popup = NULL, popupOptions = NULL, label = NULL,
labelOptions = NULL, options = pathOptions(),
highlightOptions = NULL, data = getMapData(map))
poly_map <- leaflet() %>%
setView(lng=-122.448889, lat=37.764645, zoom=12) %>%
addProviderTiles("CartoDB.Positron") %>%
# Customize the symbology of the polygons
addPolygons(data=sf_md_hhi,
color="grey", # Outline color
weight=1, # Outline thickness
fillColor="Orange",
fillOpacity = 0.25)
poly_map # color="grey", weight=1, fillColor="Orange", fillOpacity = 0.25
Median Household Income is in the estimate
column
Recipe:
estimate
Question:
What type of color function?
First, select the name of the color palette
#display.brewer.all(type="seq")
Then create the color mapping function
##
myQuantileColor_function <- colorQuantile("YlOrRd", sf_md_hhi$estimate, n=5)
A choropleth map is a graduated color map of polygon data.
choro_map <- leaflet() %>%
setView(lng=-122.448889, lat=37.764645, zoom=12) %>%
addProviderTiles("CartoDB.Positron") %>%
#
addPolygons(data=sf_md_hhi,
color="white",
weight=1,
opacity=0.5,
fillColor=~myQuantileColor_function(estimate),
fillOpacity = 0.65,
popup = paste0("$",sf_md_hhi$estimate))
choro_map # choropleth map of median household income by census tract
choro_map <- choro_map %>%
addLegend(pal = myQuantileColor_function,
values = sf_md_hhi$estimate,
title = "Median HH Income",
position="bottomleft",
opacity=1,
labFormat = function(type, cuts, p) {
n = length(cuts)
cuts = paste0("$", format(cuts[-n], big.mark=","),
" - ", "$",format(cuts[-1], big.mark=","))
}
)
choro_map # choropleth map with custom legend
You can add multiple data layers to a leaflet map.
Let’s add the sfhomes
to the map
cheap_homes <- sfhomes[sfhomes$Value < 1000000,]
choro_map2 <- choro_map %>%
# sfhomes under 1 million as points
addCircleMarkers(data=cheap_homes,
popup=paste0("$",cheap_homes$Value),
color="black",weight=1, radius=6,
fillColor="white", fillOpacity = 0.75)
choro_map2 # SF HH income and cheap homes
We can add a layer display control with addLayersControl()
.
To implemente a Layer Control you need to
assign a group
to each map layer that you want to display in the control
add the layer control and reference your groups
?addLayersControl
choro_map3 <- leaflet() %>% setView(lng=-122.448889, lat=37.764645, zoom=12) %>%
addProviderTiles("CartoDB.Positron") %>%
addPolygons(data=sf_md_hhi, color="white", weight=1, opacity=0.5,
fillColor=~myQuantileColor_function(estimate), fillOpacity = 0.65,
popup = paste0("$",sf_md_hhi$estimate),
group="Median HH Income"
) %>%
addCircleMarkers(data=cheap_homes, popup=paste0("$",cheap_homes$Value),
color="black",weight=1, radius=6,
fillColor="white", fillOpacity = 0.75,
group="Property Values"
) %>%
addLayersControl(
overlayGroups = c("Property Values","Median HH Income"),
options = layersControlOptions(collapsed = FALSE)
)
choro_map3
choro_map3 <- leaflet() %>% setView(lng=-122.448889, lat=37.764645, zoom=12) %>%
addProviderTiles("CartoDB.Positron", group="Simple Basemap") %>%
addProviderTiles("Esri.WorldStreetMap", group="Streets Basemap") %>%
addTiles("", group="No Basemap") %>%
addPolygons(data=sf_md_hhi, color="white", weight=1, opacity=0.5,
fillColor=~myQuantileColor_function(estimate), fillOpacity = 0.65,
popup = paste0("$",sf_md_hhi$estimate),
group="Median HH Income"
) %>%
addCircleMarkers(data=cheap_homes, popup=paste0("$",cheap_homes$Value),
color="black",weight=1, radius=6,
fillColor="white", fillOpacity = 0.75,
group="Property Values"
) %>%
addLayersControl(
baseGroups = c("Simple Basemap", "Streets Basemap", "No Basemap"),
overlayGroups = c("Property Values","Median HH Income"),
options = layersControlOptions(collapsed = FALSE))
choro_map3
What parameter in addLayersControl
allows you to set the layer control to be expanded or closed by default?
To you!
and to Josh Pepper who did an earlier workshop on which these materials are loosely based.
You can add an online, georectified scanned map to leaflet.
There are many of these online at the New York Public Library or MapWarper, and other websites.
Let’s add this map of Berkeley in 1880
Here we are combining addTiles
and addProviderTiles
mapurl <- "https://mapwarper.net/maps/tile/25477/{z}/{x}/{y}.png"
map2 <- leaflet() %>%
addProviderTiles("CartoDB.Positron") %>%
addTiles(mapurl) %>% # custom map image
setView(lat=37.870044, lng=-122.258169, zoom = 13)
map2 # Map of Berkeley, 1880 overlaid on the CartoDB basemap