The tidycensus and tigris packages allow for an easy way to create interactive maps of data from the Decennial census and annual American Community Survey (ACS). Combining these two packages with leaflet visualizing data from these sources is very straightforward. Much more information about using the tidycensus package can be found here.
First, I load in all the necessary packages.
######
# Code written by Daniel Cullen
# Updated Oct 2020
# Script to map ACS data at a specified
# geographic level
######
##### Load libraries
require(leaflet)
require(htmlwidgets) # to save as html
require(mapview) # for mapshot function to save leaflet as image
require(tidycensus)
require(tidyverse)
require(tigris) #for census shapefiles
options(tigris_use_cache = TRUE)
Then I will enter my personal Census API, which can be applied for here. After you enter your API key you can load the list of variables that you can use with the load_variables command. Then we can use the code for the variable and run the get_acs command and then rename and reshape so the resulting dataframe has one column called GEOID equal to the block group and one column with the variable name in this example I use population. More variables can be given to the get_acs function and addition columns will be created.
# Need to load api key on each new machine
# when install = TRUE you only need to run once
# api keys obtained from api.census.gov/data/key_signup.html
census_api_key("<INSERT YOUR KEY HERE>", install = TRUE)
###### Load ACS Data #####
# Look at variables to see codes for acs5 year estimates
#v16 <- load_variables(2016, "acs5", cache = TRUE)
acs_data <- get_acs(geography = 'block group', state = 'CA',
county = 'Santa Barbara', variables = c(population = 'B01003_001')) %>%
dplyr::select(!moe) %>%
pivot_wider(names_from = variable, values_from = c('estimate')) %>%
dplyr::select(!NAME)
Next, I load the blockgroup shape data using the tigris package. I also remove shapes that contain only water. The result is an object of types sf and data.frame.
###### Load BlockGroup Shapes #####
### Load block group shapes for county using tigris
b_groups <- block_groups(state = 'CA', county = 'Santa Barbara') %>%
filter(ALAND > 0) # Remove area that is only water
We can plot the resulting shape to check that it looks correct.
plot(b_groups$geometry)
Next we merge the ACS data to the geographic data using left_join by GEOID.
##### Merge ACS data to Shape #####
final_data <- left_join(b_groups, acs_data, by = 'GEOID')
Now we can use this final data to create our leaflet map. The map can be save as an image using mapshot and as an interactive html using saveWidget.
##### Create Map #####
### Create color palette for numeric data
### Options include Reds, Blues, Greens, Accent, RdYlBu,
### viridis, magma, inferno, plasma
pal_state_num <- colorNumeric(
palette = 'viridis',
domain = final_data$population,
na.color = NA
)
### Create Scroll over Label
labels <- sprintf(
"Population: %s people",
scales::comma(final_data$population)
) %>% lapply(htmltools::HTML)
### Create map
map <- leaflet() %>%
addProviderTiles("CartoDB.Positron") %>%
addPolygons(data = final_data,
fillColor = ~pal_state_num(population),
color = "#b2aeae", # you need to use hex colors
fillOpacity = 0.9,
weight = 0.5,
smoothFactor = 0.2,
label = labels,
labelOptions = labelOptions(
style = list('font-weight' = 'normal', padding = '3px 8px'),
textsize = '15px',
direction = 'auto')
) %>%
addLegend(position = "bottomright", pal = pal_state_num, values =final_data$population,
title = 'Population by Block Group',
opacity = 1 )
map
### Save Map as .png
mapshot(map, file = "sb_pop.png")
### Save Map as .html
saveWidget(map, file = "sb_pop.html")