#install.packages("usethis")
::use_course("https://github.com/r-journalism/nicar-2025-tidycensus/archive/master.zip")
usethis
# Run this in the console of RStudio
file.edit("04_tidycensusviz.R")
Mapping Census data
You can follow along with the 04_tidycensus_viz
file in the nicar-2025-tidycensus project folder that you downloaded in the intro link.
The repo containing the data and scripts for this section is on Github. To install those files, run the lines of code below.
To follow along with this walkthrough, simply run the lines of code in the gray boxes in the R console. Be sure to run them in order. If you run into an error, it may be because you skipped running some preceding lines of code.
Load libraries
library(tidyverse)
library(tidycensus)
library(sf)
library(mapview)
“Spatial” ACS data
One of the best features of tidycensus is the argument
geometry = TRUE
, which gets you the correct Census geometries with no hassleget_acs()
withgeometry = TRUE
returns a spatial Census dataset containing simple feature geometries;
Downloading “Spatial” ACS data
geometry = TRUE
does the hard work for you of acquiring and pre-joining spatial Census data
<- get_acs(
median_value_map geography = "tract",
state= "MN",
county="Hennepin",
variables = "B25077_001", # median values of home
year = 2022,
geometry = TRUE
)
Getting data from the 2018-2022 5-year ACS
Downloading feature geometry from the Census website. To cache shapefiles for use in future sessions, set `options(tigris_use_cache = TRUE)`.
- We get back a _simple features data frame
median_value_map
Simple feature collection with 329 features and 3 fields
Geometry type: MULTIPOLYGON
Dimension: XY
Bounding box: xmin: -93.76838 ymin: 44.78519 xmax: -93.17722 ymax: 45.24662
Geodetic CRS: NAD83
First 10 features:
GEOID estimate moe geometry
1 27053021505 306200 19165 MULTIPOLYGON (((-93.40064 4...
2 27053026713 350400 28695 MULTIPOLYGON (((-93.43159 4...
3 27053000102 219300 13782 MULTIPOLYGON (((-93.29919 4...
4 27053108700 260500 15666 MULTIPOLYGON (((-93.24235 4...
5 27053102100 193400 22082 MULTIPOLYGON (((-93.3082 45...
6 27053026814 260200 13156 MULTIPOLYGON (((-93.3211 45...
7 27053023802 529500 79402 MULTIPOLYGON (((-93.32898 4...
8 27053100800 192800 21081 MULTIPOLYGON (((-93.30833 4...
9 27053125800 195900 38910 MULTIPOLYGON (((-93.26259 4...
10 27053025403 273600 8221 MULTIPOLYGON (((-93.28698 4...
Exploring Census data interactively
library(mapview)
mapview(median_value_map)
Creating a shaded map with zcol
mapview(median_value_map, zcol = "estimate")
Try all the code again in a different county
<- get_acs(
median_value_map geography = "tract",
state= "MN", # Changeme
county="Hennepin", # Change me
variables = "B25077_001", # median values of home
year = 2022,
geometry = TRUE
)
mapview(median_value_map, zcol = "estimate")
Migration data
Let’s map some county-to-county migration data from the Census! [Link]
<- get_flows(
county_migration geography = "county",
county = "Hennepin",
state = "MN"
)
county_migration
# A tibble: 2,496 × 7
GEOID1 GEOID2 FULL1_NAME FULL2_NAME variable estimate moe
<chr> <chr> <chr> <chr> <chr> <dbl> <dbl>
1 27053 <NA> Hennepin County, Minnesota Africa MOVEDIN 2015 519
2 27053 <NA> Hennepin County, Minnesota Africa MOVEDOUT NA NA
3 27053 <NA> Hennepin County, Minnesota Africa MOVEDNET NA NA
4 27053 <NA> Hennepin County, Minnesota Asia MOVEDIN 3877 581
5 27053 <NA> Hennepin County, Minnesota Asia MOVEDOUT NA NA
6 27053 <NA> Hennepin County, Minnesota Asia MOVEDNET NA NA
7 27053 <NA> Hennepin County, Minnesota Central Ame… MOVEDIN 646 198
8 27053 <NA> Hennepin County, Minnesota Central Ame… MOVEDOUT NA NA
9 27053 <NA> Hennepin County, Minnesota Central Ame… MOVEDNET NA NA
10 27053 <NA> Hennepin County, Minnesota Caribbean MOVEDIN 82 64
# ℹ 2,486 more rows
Downloading map data
<- get_acs(
county_map geography = "county",
variable = c("Population"="B03002_001"),
geometry = TRUE
)
Getting data from the 2019-2023 5-year ACS
Downloading feature geometry from the Census website. To cache shapefiles for use in future sessions, set `options(tigris_use_cache = TRUE)`.
county_map
Simple feature collection with 3222 features and 5 fields
Geometry type: MULTIPOLYGON
Dimension: XY
Bounding box: xmin: -179.1467 ymin: 17.88328 xmax: 179.7785 ymax: 71.38782
Geodetic CRS: NAD83
First 10 features:
GEOID NAME variable estimate moe
1 01003 Baldwin County, Alabama Population 239945 NA
2 01069 Houston County, Alabama Population 107628 NA
3 01005 Barbour County, Alabama Population 24757 NA
4 01119 Sumter County, Alabama Population 12020 NA
5 05091 Miller County, Arkansas Population 42588 NA
6 05133 Sevier County, Arkansas Population 15797 NA
7 05093 Mississippi County, Arkansas Population 39749 NA
8 06037 Los Angeles County, California Population 9848406 NA
9 06087 Santa Cruz County, California Population 266021 NA
10 06097 Sonoma County, California Population 485642 NA
geometry
1 MULTIPOLYGON (((-88.02858 3...
2 MULTIPOLYGON (((-85.71209 3...
3 MULTIPOLYGON (((-85.74803 3...
4 MULTIPOLYGON (((-88.41492 3...
5 MULTIPOLYGON (((-94.04343 3...
6 MULTIPOLYGON (((-94.47732 3...
7 MULTIPOLYGON (((-90.2888 35...
8 MULTIPOLYGON (((-118.6044 3...
9 MULTIPOLYGON (((-122.3177 3...
10 MULTIPOLYGON (((-123.5335 3...
Prep the migration data
<- county_migration |>
county_migration_moved filter(variable=="MOVEDIN") |>
filter(!is.na(GEOID2)) |>
select(GEOID=GEOID2, migration=estimate)
Join the migration data with the shapefile
<- county_map %>%
county_map_migration inner_join(county_migration_moved)
mapview(county_map_migration, zcol = "migration")
Can you map migration out?
<- county_migration |>
county_migration_moved filter(variable=="MOVEDOUT") |>
filter(!is.na(GEOID2)) |>
select(GEOID=GEOID2, migration=estimate)
<- county_map %>%
county_map_migration inner_join(county_migration_moved)
mapview(county_map_migration, zcol = "migration")
More resources
- R-Journalism: How to make static maps with Census data
- R-Journalism: Traffic stops case study