Same data, two maps

Below is the now-familiar table of small-area fair market rent estimates for Rutherford County ZIP codes, followed by two maps of the data.

The first map, ZIP codes by rent category, emphasizes which ZIP codes have above-average rents and which ZIP codes have below-average rents. You learned how to make this map during a previous class. The second map, ZIP codes by average rent, has been customized to use increasingly darker shades of green to highlight ZIP codes with increasingly expensive average rents.

Today’s class is about learning how to customize R-based data maps in this and other ways.

Rutherford FMR, by size and ZIP
ZIP Studio BR1 BR2 BR3 BR4 ZIP_Average Rent_Category
37037 1660 1710 1920 2410 2940 2128 Above average
37086 1580 1620 1820 2290 2790 2020 Above average
37128 1510 1550 1740 2190 2670 1932 Above average
37129 1420 1460 1640 2060 2510 1818 Above average
37153 1410 1450 1630 2040 2490 1804 Above average
37167 1290 1330 1490 1870 2280 1652 Below average
37085 1260 1290 1450 1820 2210 1606 Below average
37127 1240 1270 1430 1800 2190 1586 Below average
37130 1180 1210 1360 1710 2080 1508 Below average
37132 1180 1210 1360 1710 2080 1508 Below average
37118 1100 1130 1270 1590 1960 1410 Below average
37149 1100 1130 1270 1590 1960 1410 Below average

ZIP codes by rent category


ZIP codes by average rent


Remaking the basic map

Copy and run this code to remake the first map - the one that simply distinguishes between ZIP codes with “Above average” and “Below average” overall rent estimates.

# Getting and loading required packages

if (!require("tidyverse"))
  install.packages("tidyverse")
if (!require("gtExtras"))
  install.packages("gtExtras")
if (!require("leafpop"))
  install.packages("leafpop")
if (!require("sf"))
  install.packages("sf")
if (!require("mapview"))
  install.packages("mapview")
if (!require("RColorBrewer"))
  install.packages("RColorBrewer")

library(tidyverse)
library(gtExtras)
library(sf)
library(mapview)
library(leafpop)
library(RColorBrewer)

# Reloading the rent data

FMR_RuCo <- read_csv("https://raw.githubusercontent.com/drkblake/Data/refs/heads/main/FMR_RuCo.csv")

# Showing the rent data

FMR_RuCo_table <- gt(FMR_RuCo) %>%
  tab_header("Rutherford FMR, by size and ZIP") %>%
  cols_align(align = "left") %>%
  gt_theme_538
FMR_RuCo_table

# Downloading the ZIP code map file

download.file(
  "https://www2.census.gov/geo/tiger/GENZ2020/shp/cb_2020_us_zcta520_500k.zip",
  "ZCTAs2020.zip"
)

# Unzipping the ZIP code map file

unzip("ZCTAs2020.zip")

# Loading the ZIP code file into R as "ZCTAMap"

ZCTAMap <- read_sf("cb_2020_us_zcta520_500k.shp")

# Making ZIP a character variable

FMR_RuCo$ZIP <- as.character(FMR_RuCo$ZIP)

# Joining the files

FMR_RuCo_Map <- left_join(FMR_RuCo, ZCTAMap, by = c("ZIP" = "ZCTA5CE20"))

# Dropping unneeded columns

FMR_RuCo_Map <- FMR_RuCo_Map %>%
  select(-c(AFFGEOID20, GEOID20, NAME20, LSAD20, ALAND20, AWATER20))

# Converting FMR_RuCo_Map

FMR_RuCo_Map <- st_as_sf(FMR_RuCo_Map)

# Making the map

Rent_Category_Map <- mapview(
  FMR_RuCo_Map,
  zcol = "Rent_Category",
  layer.name = "Rent category",
  popup = popupTable(
    FMR_RuCo_Map,
    feature.id = FALSE,
    row.numbers = FALSE,
    zcol = c("ZIP", "Studio", "BR1", "BR2", "BR3", "BR4")
  )
)

# Showing the map

Rent_Category_Map

Switching the map’s key to “ZIP code”

Switching a mapview map’s “key” is as simple as changing the data frame variable that the mapview() function’s zcol argument points to. For example, to switch from the “ZIP codes by rent category” map to one with a key that shows each ZIP code, simply change:

zcol = "Rent_Category" to zcol = "ZIP"

And to change the key’s heading to reflect what the key shows, change:

layer.name = "Rent category" to layer.name = "ZIP code"

You can leave all of the other mapview() arguments unchanged. Note, too, that whatever variable you point the zcol argument toward is the one that “pops up” as you hover over the map’s regions. Here’s the code and the resulting map:

# Mapping by ZIP code

ZIP_Map <- mapview(
  FMR_RuCo_Map,
  zcol = "ZIP",
  layer.name = "ZIP code",
  popup = popupTable(
    FMR_RuCo_Map,
    feature.id = FALSE,
    row.numbers = FALSE,
    zcol = c("ZIP", "Studio", "BR1", "BR2", "BR3", "BR4")))

# Showing the map

ZIP_Map

Changing the map’s colors

I’m not sure the ZIP code emphasis is all that helpful. Let’s change the focus to the ZIP_Average variable by:

Changing zcol = "ZIP" to zcol = "ZIP_Average"

Changing layer.name = "ZIP code" to layer.name = "Average rent"

And while we’re at it, let’s change the map’s color scheme. The one in the ZIP code map is the one the mapview() function gives you by default. To get other schemes, load the RColorBrewer package, which we did in the first block of code:

if (!require("RColorBrewer")) install.packages("RColorBrewer")

… then specify a color scheme by placing the RColorBrewer package’s brewer.pal() function among the mapview() function’s arguments. The brewer.pal() function requires two arguments: the number of shades in the scheme you have chosen, and the scheme’s name. Here’ we’ll use the BuGn scheme, which has nine shades:

col.regions = brewer.pal(9, "BuGn")

… and put it right after the mapview() function’s zcol argument. Here’s the whole thing, and the results:

# Mapping by ZIP_Average

Avg_Rent_Map <- mapview(
  FMR_RuCo_Map,
  zcol = "ZIP_Average",
  col.regions = brewer.pal(9, "BuGn"),
  layer.name = "Average rent",
  popup = popupTable(
    FMR_RuCo_Map,
    feature.id = FALSE,
    row.numbers = FALSE,
    zcol = c("ZIP", "Studio", "BR1", "BR2", "BR3", "BR4")))

# Showing the map

Avg_Rent_Map

What other color schemes are there?

RColorBrewer offers 35 color schemes. You can see all of them by running this code:

display.brewer.all()

… which will get you something like the chart below. The name of each color scheme is on the left. Count the shades in a given color scheme to get the number for the first argument in the brewer.pal() function:

Making comparison maps

One more trick up the mapview package’s sleeve: If you have generated two maps, you can arrange them in ways that make it easy to compare them.

Making a slider map

One approach, for example, is to put one on top of the other, then add a vertical “slider bar” that will uncover one map and hide the other. The result is called a “slider map.”

Here’s some code that regenerates the Rent_Category_Map, from above, but changes its color scheme to two-tone grey (because the original yellow and purple would look terrible), then combines it and the Avg_Rent_Map into a slider map:

Rent_Category_Map <- mapview(
  FMR_RuCo_Map,
  zcol = "Rent_Category",
  col.regions = brewer.pal(2, "Greys"),
  layer.name = "Rent category",
  popup = popupTable(
    FMR_RuCo_Map,
    feature.id = FALSE,
    row.numbers = FALSE,
    zcol = c("ZIP", "Studio", "BR1", "BR2", "BR3", "BR4")
  )
)

Rent_Category_Map | Avg_Rent_Map

Making a side-by-side map

A side-by-side map offers a second way to compare two maps. As the name implies, both maps get shown side-by-side, and the cursor is synchronised, so that hovering over and area in one map highlights the same area in the other map.

Making one requires installing and loading the leafsync package, then using the package’s sync() function with each map name as an argument. Below is the code, followed by the resulting map.

if (!require("leafsync"))
  install.packages("leafsync")

library(leafsync)

sync(Rent_Category_Map, Avg_Rent_Map)

In-class exercise

Make all four of the maps above - the Rent Category map, the ZIP Code map, the slider map, and the side-by-side map - but choose a different color scheme. The “Blues” scheme is a favorite of mine. But fiddle around a bit to find one you like.

When your maps look the way you want them to, use R Markdown to publish them, along with their code, on RPubs.com. Show me your work before the end of class, and you will be free to leave early.