Mapping ACS data with tidycensus and tigris

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")