The data used in this report is freely available from the Bureau of Transportation Statistics: Congressional Districts.
With redistricting being a hot topic for many states in 2025 and 2026, a refresher on current Congressional Districts is due. For this report, I will focus on Illinois, whose governor, JB Pritzker, has not ruled out the possibility in the near future. Illinois certainly has some interestingly-shaped districts, and is considered one of the most gerrymandered states in the country by Princeton’s Gerrymandering Project.
Without further ado, let’s look at some gerrymandered districts!
library(leaflet)
library(sf)
library(tidyverse)
library(USAboundaries)
districts = st_read("districts.csv") # load the csv
## Reading layer `districts' from data source
## `C:\Users\Brianne\Documents\588\Lesson 4\Part B\Leaflet\districts.csv'
## using driver `CSV'
glimpse(districts)
## Rows: 444
## Columns: 43
## $ OBJECTID <chr> "1", "2", "3", "4", "5", "6", "7", "8", "9", "10…
## $ STATEFP <chr> "01", "01", "01", "01", "01", "01", "01", "02", …
## $ CD119FP <chr> "01", "02", "03", "04", "05", "06", "07", "00", …
## $ GEOID <chr> "0101", "0102", "0103", "0104", "0105", "0106", …
## $ GEOIDFQ <chr> "5001900US0101", "5001900US0102", "5001900US0103…
## $ NAMELSAD <chr> "Congressional District 1", "Congressional Distr…
## $ LSAD <chr> "C2", "C2", "C2", "C2", "C2", "C2", "C2", "C1", …
## $ CDSESSN <chr> "119", "119", "119", "119", "119", "119", "119",…
## $ MTFCC <chr> "G5200", "G5200", "G5200", "G5200", "G5200", "G5…
## $ FUNCSTAT <chr> "N", "N", "N", "N", "N", "N", "N", "N", "N", "N"…
## $ ALAND <chr> "18753464839", "24514317067", "17327582348", "22…
## $ AWATER <chr> "2274273696", "234734076", "466368976", "5787546…
## $ INTPTLAT <chr> "+31.0328895", "+31.7619148", "+33.4140097", "+3…
## $ INTPTLON <chr> "-086.7989750", "-086.6281876", "-085.7577724", …
## $ OFFICE_ID <chr> "AL01", "AL02", "AL03", "AL04", "AL05", "AL06", …
## $ BIOGUIDE_ID <chr> "M001212", "F000481", "R000575", "A000055", "S00…
## $ OFFICE_AUDIT_ID <chr> "00010965", "00010966", "00006997", "00004973", …
## $ PREFIX <chr> "Mr. ", "Mr. ", "Mr. ", "Mr. ", "Mr. ", "Mr. ", …
## $ FIRSTNAME <chr> "Barry", "Shomari", "Mike", "Robert", "Dale", "G…
## $ MIDDLENAME <chr> "", "", "", "B.", "W.", "J.", "A.", "J.", "", "A…
## $ LASTNAME <chr> "Moore", "Figures", "Rogers", "Aderholt", "Stron…
## $ SUFFIX <chr> "", "", "", "", "", "", "", "III", "", "", "", "…
## $ LISTING_NAME <chr> "Moore, Barry", "Figures, Shomari", "Rogers, Mik…
## $ PHONE <chr> "52901", "54931", "53261", "54876", "54801", "54…
## $ WEBSITEURL <chr> "https://barrymoore.house.gov", "https://figures…
## $ VACANT <chr> "N", "N", "N", "N", "N", "N", "N", "N", "N", "N"…
## $ CONTACTFORMURL <chr> "https://barrymoore.house.gov/address_authentica…
## $ PHOTOURL <chr> "https://ziplook.house.gov/zip/pictures/al02_moo…
## $ FACE_BOOK_URL <chr> "https://www.facebook.com/RepBarryMoore/", "http…
## $ TWITTER_URL <chr> "https://x.com/repbarrymoore", "", "https://twit…
## $ YOUTUBE_URL <chr> "", "", "https://www.youtube.com/user/MikeRogers…
## $ INSTAGRAM_URL <chr> "https://www.instagram.com/repbarrymoore", "", "…
## $ FLICKR_URL <chr> "", "", "", "", "", "", "http://www.flickr.com/p…
## $ PARTY <chr> "R", "D", "R", "R", "R", "R", "D", "R", "D", "R"…
## $ DISTRICT <chr> "01", "02", "03", "04", "05", "06", "07", "00", …
## $ STATE <chr> "", "", "", "", "", "", "", "", "", "", "", "", …
## $ VACANCY <chr> "", "", "", "", "", "", "", "", "", "", "", "", …
## $ ROOM_NUM <chr> "1504", "225", "2469", "266", "1337", "170", "10…
## $ HOB <chr> "LHOB", "CHOB", "RHOB", "CHOB", "LHOB", "CHOB", …
## $ COMMITTEE_ASSIGNMENTS <chr> "Agriculture;the Judiciary", "Agriculture;Transp…
## $ LAST_UPDATED <chr> "", "", "", "", "", "", "", "", "", "", "", "", …
## $ Shape__Area <chr> "28726339726.4082", "34338167972.9707", "2560799…
## $ Shape__Length <chr> "1538555.73153839", "1746535.87670029", "956459.…
Interestingly, the csv file does not contain the data required to create polygons for the congressional districts, but it does include point data in the INTPTLON and INTPTLAT columns.
districts_il <- districts %>%
# rename to a recognizable format for leaflet, eg. lat/lon
rename(lat = INTPTLAT, lng = INTPTLON) %>%
# mutate() lat and lon columns to convert strings to numerals
mutate(lat = as.numeric(lat), lng = as.numeric(lng)) %>%
# filter to Illinois only
filter(STATEFP == 17, NAMELSAD != "Congressional Districts not defined") %>%
#using select() ensures that only the columns I need are included
select(district = `NAMELSAD`, representative = `LISTING_NAME`, contact = `CONTACTFORMURL`, party = `PARTY`, lat, lng)
glimpse(districts_il)
## Rows: 17
## Columns: 6
## $ district <chr> "Congressional District 13", "Congressional District 3"…
## $ representative <chr> "Budzinski, Nikki", "Ramirez, Delia", "Schakowsky, Jani…
## $ contact <chr> "https://budzinski.house.gov/contact", "https://ramirez…
## $ party <chr> "D", "D", "D", "D", "D", "D", "R", "D", "R", "D", "D", …
## $ lat <dbl> 39.12803, 41.93579, 42.24340, 41.41760, 42.02767, 41.56…
## $ lng <dbl> -90.00985, -87.97443, -88.08998, -87.95205, -88.19718, …
Only the necessary information remains after using filter() and select().
The USABoundaries library has congressional district boundaries, which I can join to districts_il.
# get congressional boundaries for Illinois with USABoundaries
boundaries_il <- us_congressional(state = "Illinois")
# join districts_il to boundaries_il
districts_il <- boundaries_il %>%
left_join(districts_il, by = c("namelsad" = "district"))
glimpse(districts_il)
## Rows: 17
## Columns: 18
## $ statefp <chr> "17", "17", "17", "17", "17", "17", "17", "17", "17"…
## $ cd119fp <chr> "04", "06", "02", "09", "08", "15", "10", "07", "11"…
## $ geoidfq <chr> "5001900US1704", "5001900US1706", "5001900US1702", "…
## $ geoid <chr> "1704", "1706", "1702", "1709", "1708", "1715", "171…
## $ namelsad <chr> "Congressional District 4", "Congressional District …
## $ lsad <chr> "C2", "C2", "C2", "C2", "C2", "C2", "C2", "C2", "C2"…
## $ cdsessn <chr> "119", "119", "119", "119", "119", "119", "119", "11…
## $ aland <dbl> 248008492, 583310409, 10144448787, 434425556, 739319…
## $ awater <dbl> 3103417, 11810373, 38966582, 11571696, 15208390, 609…
## $ state_name <chr> "Illinois", "Illinois", "Illinois", "Illinois", "Ill…
## $ state_abbr <chr> "IL", "IL", "IL", "IL", "IL", "IL", "IL", "IL", "IL"…
## $ jurisdiction_type <chr> "state", "state", "state", "state", "state", "state"…
## $ representative <chr> "Garcia, Jesus", "Casten, Sean", "Kelly, Robin", "Sc…
## $ contact <chr> "https://chuygarcia.house.gov/contact/email-me", "ht…
## $ party <chr> "D", "D", "D", "D", "D", "R", "D", "D", "D", "D", "D…
## $ lat <dbl> 41.82937, 41.73695, 40.77148, 42.24340, 42.02767, 39…
## $ lng <dbl> -87.80990, -87.89288, -87.94265, -88.08998, -88.1971…
## $ geometry <MULTIPOLYGON [°]> MULTIPOLYGON (((-87.92042 4..., MULTIPO…
The datasets appear to have joined successfully.
# define a palette for the legend
pal <- colorFactor(
palette = c("D" = "blue", "R" = "red"),
domain = districts_il$party
)
# add the basemap (default OSM tiles)
leaflet(districts_il) %>%
# set coordinates to center on Illinois
setView(lng=-89.4, lat=40.63, zoom = 6) %>%
addTiles() %>%
# add the congressional district polygons
addPolygons(
fillColor = ~pal(party),
fillOpacity = 0.5,
color = "white", # white borders (default blue)
weight = 1, # decrease default border weight
label = ~namelsad, # label congressional district number
# add line breaks to separate representative name and contact URL
popup = ~paste0("<b>", representative, "</b><br>", contact)) %>%
# add a simple legend in the bottom right corner
addLegend(position = "bottomright",
pal = pal,
values = ~party,
title = "Party")
The result is a map of Illinois 2025 Congressional Districts, complete with a color legend for party affiliation, labels describing the district on hover, and popups providing representative name and contact website for each district.