Mapping with Leaflet

By Joseph M. Westenberg

This post assumes a basic knowledge of R.

Using leaflet we can map shapefiles and specific points. As an illustrative example I will be using code I wrote earlier this year when I was looking into some questions regarding schools and state government. The shapefiles I will be using are the lower and upper legislatures for the state of Wisconsin. The points I will be mapping in the second post of this series will be specific school locations.Si

The goal of this post is to explain how to make an interactive map as below. This map allows user interaction: zooming in and out, clicking on areasto show details of that area, removing or adding of layers (top right corner).

The main libraries we will be using are tigris and leaflet. Let’s start by loading these packages and then downloading the lower and upper legislative district shapefiles via tigris.

library(tigris)
library(leaflet)
WiscoCdUpper<-state_legislative_districts(state="WI", house = "upper", 
  year=2013, cb=TRUE)
WiscoCdLower<-state_legislative_districts(state="WI", house = "lower", 
  year=2013, cb=TRUE)
centerLNG<--90
centerLAT<-44.8

The arguments arguments are fairly self explanatory:

  • state: the state that you want to retrieve shapefiles for. Accepts State FIPS or state abbreviation.
  • house: indicates which legislative districts you want. Takes lower or upper as an argument
  • year: the districts that were active in this year
  • cb: an argument for adjusting level of detail. FALSE is default and is the high detail map. TRUE returns a less detailed map.

The variables centerLNG and centerLAT are longitude and latitude coordinate that I will be using to center my map around.

The interactive mapping package I use is leaflet, it will allow us to layer different shapefiles over a base map.

I first want to store this information that will be popping up to a vector to feed into leaflet’s command. Now within our spatial polygon data frame, we can access the ID of each shape. these take the form of SSDDD where SS is a two digit state FIPS code, and DDD is a 3 digit district number.

districtinfo <- paste0("Lower District: ", substr(WiscoCdLower$GEOID, 3, 5))
mapcolors<-rainbow(length(WiscoCdLower$GEOID))
rnum<-sample(nrow(WiscoCdLower))
pal <- colorFactor(mapcolors[rnum], WiscoCdLower$GEOID)
lowermap<-leaflet(options = leafletOptions(minZoom = 4)) %>%
  addProviderTiles("CartoDB.Positron", group = "base") %>%
  setView(centerLNG, centerLAT, zoom = 6) %>%
  setMaxBounds(-94, 41, -85, 48) %>%
  addPolygons(data = WiscoCdLower, color = "white", weight = 2,
    fillColor = ~pal(GEOID), fillOpacity = 0.5, popup = districtinfo, 
    group = "Lower") %>%
  addLayersControl(baseGroups = c("base"), overlayGroups = c("Lower"))

Going line by line:

  1. Define the text that we want to appear in the information when users click an area of the map
  2. Define a vector of colors with length equal to the number of districts
  3. Since our code in line 2 would have similar colors next to each other, I want to shuffle the colors to make it look better (more info here)
  4. Create a dataframe with color information and an id for each district.
  5. Leaflet conveniently allows for piping. To start the map generation, lets limit users to only be able to zoom out so far.
  6. This provides a base map where we will lay our other shapes on top of. We can label this so we can refer to it later (in line 12).
  7. This sets the initial view, centered on a latitude and longitude point with a certain initial zoom
  8. To restrict the user from venturing too far from your area of interest you can restrict the frame of the map. To see this, try to pull the map in any direction, you can’t get too far until it bounces you back to a relevant frame.
  9. Here is where we layer our district shapefile on top of that base map we established in line 6. Leaflet recognizes the Spatial Polygon Dataframe as such and knows how to handle it. The color option sets the color of the border of the districts and the weight is how thick these borders are.
  10. Continuing with the district shapefile options. To fill the shapes with different colors, we use the colors we generated in lines 2-4. The fillOpacity command allows you to adjust how much you can see through the shape. Notice how you can still make out information on the base map? That’s because we set this option to less than 1. The popup option is telling leaflet we want to see districtinfo for the area we are clicking on in the map.
  11. We can label this layer as “Lower,” this allows us to refer to it in the layers control below.
  12. Lastly, this layer control allows us to tell leaflet that we want the “base” to always be visible on the map, but we can add/remove “Lower.” To see this in the map below click the icon in the upper right corner. Notice how we can uncheck and recheck “Lower?” But we can’t do that with the base map.

We can then add an additional layer to this map with the upper house as well.

districtinfo <- paste0("Lower District: ", substr(WiscoCdLower$GEOID,3,5),
  " <br> ", "Upper District: ", substr(WiscoCdUpper$GEOID,3,5))
loweranduppermap<-leaflet(options = leafletOptions(minZoom = 4)) %>%
  addProviderTiles("CartoDB.Positron", group = "base") %>%
  setView(centerLNG, centerLAT, zoom = 6) %>%
  setMaxBounds(-94, 41, -85, 48) %>%
  addPolygons(data = WiscoCdLower, color = "white", weight = 2,
    fillColor = ~pal(GEOID), fillOpacity = 0.5, 
    popup = districtinfo, group = "Lower") %>%
  addPolygons(data = WiscoCdUpper, weight =2, opacity = 1,
    color = "black", fill = FALSE, group = "Upper") %>%
  addLayersControl(baseGroups = c("base"), 
    overlayGroups = c("Upper", "Lower"))

There are only a few changes we needed to make. In line 1 and 2 we define our pop up to show information on both the lower and upper legislative districts. In lines 10 and 11 we add in the upper house as an additional layer. Setting fill to false we can just have the boundary of the upper legislative districts, this will allow us to see through to the lower legislative district layer. And lastly in line 12 and 13 we add our upper legislative districts into the map. Notice if you open the layer control in the map below (upper right corner), you can now check/uncheck both the lower and the upper legislative districts.

Posted on:
July 14, 2021
Length:
5 minute read, 1013 words
See Also: