Acquire, clean, and format ACS median household and family income
data with geometries
library(tidycensus)
library(tidyverse)
library(tigris)
library(sf)
library(zctaCrosswalk)
library(htmlwidgets)
options(tigris_use_cache = TRUE)
# variables_ACS2022 <- load_variables(2022, "acs5/profile")
year <- 2022 # year of interest
# GEOIDs of NYC counties/boroughs
NYC_county_GEOIDs <- c(36005, 36047, 36061, 36081, 36085)
# FIPS code of NYC counties/boroughs
NYC_county_FIPS <- c(005, 047, 061, 081, 085)
# get ACS median family income (MFI) and median household income (MHI) by county
nyc_county_income <- get_acs(
survey = "acs5",
geography = "county",
state = 36,
variables = c(mhi = "DP03_0062", mfi = "DP03_0086"),
year = year,
geometry = TRUE,
cb = FALSE # use core TIGER/Line shapefiles for shoreline mapping
) %>%
select(-moe) %>%
pivot_wider(names_from = variable, values_from = estimate) %>%
filter(GEOID %in% NYC_county_GEOIDs) %>%
st_transform(4326) %>%
erase_water(year = year) %>%
# convert geomcol to multipolygon
st_collection_extract(type = c("POLYGON", "POINT", "LINESTRING")) %>%
st_make_valid()
# get ACS median family income (MFI) and median household income (MHI) by ZCTA
nyc_zcta_income <- get_acs(
survey = "acs5",
geography = "zcta",
variables = c(mhi = "DP03_0062", mfi = "DP03_0086"),
year = year,
geometry = TRUE,
cb = FALSE # use core TIGER/Line shapefiles for shoreline mapping
) %>%
filter(GEOID %in% get_zctas_by_county(NYC_county_GEOIDs)) %>%
select(-moe) %>%
pivot_wider(names_from = variable, values_from = estimate) %>%
st_transform(4326) %>%
erase_water(year = year) %>%
# convert geomcol to multipolygon
st_collection_extract(type = c("POLYGON", "POINT", "LINESTRING")) %>%
st_make_valid()
# get ACS median family income (MFI) and median household income (MHI) by Tract
nyc_tract_income <- get_acs(
survey = "acs5",
geography = "tract",
state = 36,
county = NYC_county_FIPS,
variables = c(mhi = "DP03_0062", mfi = "DP03_0086"),
year = year,
geometry = TRUE,
cb = FALSE # use core TIGER/Line shapefiles for shoreline mapping
) %>%
select(-moe) %>%
pivot_wider(names_from = variable, values_from = estimate) %>%
st_transform(4326) %>%
erase_water(year = year) %>%
# convert geomcol to multipolygon
st_collection_extract(type = c("POLYGON", "POINT", "LINESTRING")) %>%
st_make_valid()
# read in shapefile of NYC 2020 community district tabulations areas (CDTAs)
nyc_cdtas <- read_sf("../data/vector/raw/nycdta2020_24c/nycdta2020.shp") %>%
st_transform(4326)
# read in ACS 5-year 2018-2022 economic data by CDTA, provided by NYC DCP
# filter for identifying info and household/family income
nyc_cdta_income <-
read_csv("../data/tabular/raw/NYC-DCP_ACS5_1822_CDTA_Econ.csv") %>%
select(GeoType, CDTAType, GeogName, GeoID, Borough, MdHHIncE, MdFamIncE) %>%
rename(mhi = MdHHIncE,
mfi = MdFamIncE,
NAME = GeogName)
# join the CDTA geometries to the income data
nyc_cdta_income <- left_join(nyc_cdta_income,
nyc_cdtas[, c("CDTA2020", "geometry")],
by = join_by(GeoID == CDTA2020)) %>%
st_as_sf()
Use income data to create leaflet maps for each scale
library(sf)
library(leaflet)
library(classInt)
# Function for creating a leaflet map of ACS median household income at
# various scales
create_lfmap <- function(data, title, borderWeight) {
# Define a color palette using Fisher-Jenks
pal <- colorBin(palette = "Greens",
bins = classIntervals(data$mhi,
n = 5,
style = "fisher")$brks,
pretty = FALSE)
# Hover label text
labels <- sprintf(
"<span style='font-size: 20px'><b>%s</b></span><br/>
2022 Median household income: <strong>$%s</strong><br/>
MFI - MHI = $%s",
data$NAME,
prettyNum(data$mhi, big.mark = ","),
prettyNum(data$mfi - data$mhi, big.mark = ",")
) %>% lapply(htmltools::HTML)
# Create the leaflet map
leaflet(data = data,
options = leafletOptions(
zoomControl = TRUE,
zoomSnap = 0.25,
zoomDelta = 1)) %>%
addProviderTiles("CartoDB.DarkMatter") %>%
addPolygons(fillColor = ~pal(mhi),
weight = borderWeight,
opacity = 1,
color = "white",
dashArray = "7",
fillOpacity = 0.7,
highlightOptions = highlightOptions(
weight = 5,
color = "white",
dashArray = "",
fillOpacity = 0.7,
bringToFront = TRUE),
label = labels,
labelOptions = labelOptions(
style = list("font-weight" = "normal", padding = "3px 8px"),
textsize = "15px",
direction = "auto")) %>%
addLegend(pal = pal,
values = ~mhi,
opacity = 0.7,
title = title,
position = "bottomright")
}
# Create a leaflet map for each scale
nyc_county_map <-
create_lfmap(nyc_county_income, "NYC Median Household Income by County", 2)
nyc_cdta_map <-
create_lfmap(nyc_cdta_income, "NYC Median Household Income by CDTA", 1)
nyc_zcta_map <-
create_lfmap(nyc_zcta_income, "NYC Median Household Income by ZCTA", 1)
nyc_tract_map <-
create_lfmap(nyc_tract_income, "NYC Median Household Income by Tract", 0.75)
Leaflet map outputs
nyc_county_map
nyc_cdta_map
nyc_zcta_map
nyc_tract_map