front-line house democrats: a quick guide

[This article was first published on Jason Timm, and kindly contributed to R-bloggers]. (You can report issue about the content on this page here)
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.


So, with an impeachment vote nigh and the 2020 general elections slowly approaching, lots of talk about the 31 House Democrats that represent congressional districts won by the sitting president in 2016. Here, we present a quick/simple/R-based investigation into the composition of this group of Democrats from several different perspectives. We also consider the 43 congressional districts that flipped Democratic in the 2018 midterms.

Pundits constantly cite these districts and count them in different ways; and I am constantly trying to recreate these counts. As open source federal election data can be a bit of a mess, this is an attempt to organize & collate some data sources.

House & presidential election returns

The R data package uspoliticalextras includes federal election returns from a couple of sources, namely the Daily Kos and the MIT Election Data and Science Lab. I use the package as a bit of a cache for US political data; it is available via Git Hub. The focus here will be on the last Presidential election (2016) & the last two House races (2016 & 2018).

library(tidyverse)
#devtools::install_github("jaytimm/uspoliticalextras")  
pres <- uspoliticalextras::uspol_dkos_returns_pres_cd 
house <- uspoliticalextras::uspol_medsl_returns_house_cd %>%
  filter(year > 2015) %>%
  mutate(party = ifelse(party == 'Independent', 'Republican Party', party)) # Amash

Trump margins in 2016

Number of congressional districts carried by DJT & HRC.

pres %>%
  filter(year == 2016) %>%
  group_by(candidate) %>%
  count() %>%
  knitr::kable()
candidaten
Clinton205
Trump230

Trump margins by congressional district in 2016.

library(sf)
to_map <- uspoliticalextras::uspol_dkos_equalarea_sf$hex_cds %>%
  select(GEOID) %>%
  left_join(pres %>% 
              filter(year == 2016) %>% 
              mutate(trump_margin = republican - democrat),
            by = 'GEOID') 
to_map %>%
  ggplot() + 
  geom_sf(aes(fill = trump_margin),
          color = 'white') +
  geom_sf(data=uspoliticalextras::uspol_dkos_equalarea_sf$hex_states, 
          fill = NA, 
          show.legend = F, 
          color="#5a5c5b", 
          lwd=.5) +
  ggsflabel::geom_sf_text(data = uspoliticalextras::uspol_dkos_equalarea_sf$hex_cds,
                          aes(label = district_code), 
                          size = 2,
                          color='black') +
  scale_fill_distiller(palette = "RdBu", direction=-1) +
  theme_minimal()+
  theme(axis.text.x=element_blank(),
        axis.text.y=element_blank(),
        axis.title.x=element_blank(),
        axis.title.y=element_blank(),
        legend.position = 'none') +
  labs(title = "2016 Trump Margins by Congressional District",
       caption = 'Source: Daily Kos')

Flipped House Districts from 2016 to 2018

Congressional districts that elected a Republican representative in 2016 and a Democratic representative in 2018.

house_flips <- house %>%
  select(GEOID, congress,party) %>%
  spread(congress, party) %>%
  left_join(house %>% 
              filter(year == 2018) %>% 
              mutate(house_rep_margin = round(republican - democrat, 1)) %>%
              select(GEOID, state, district_code, candidate, house_rep_margin) %>% 
              rename(house_rep = candidate))

Some corrections/amendments for Pennsylvania districts per 2019 redistricting.

pa16_rs <- c('4201', '4205', '4206',
           '4207', '4209', '4210',
           '4211', '4212', '4213','4215',
           '4216', '4217')
pa16_ds <- c('4202', '4203', '4204',
           '4208',  '4214',
           '4218')
pa18_rs <- c('4203', '4204', '4205', '4218')
pa18_ds <- c('4213', '4214')
house_flips1 <-  house_flips %>%
  mutate(`115` = ifelse(GEOID %in% pa16_rs, 'Republican Party', `115`),
         `115` = ifelse(GEOID %in% pa16_ds, 'Democratic Party', `115`)) %>%
  mutate(house_flip = paste0(`115`, ' | ', `116`)) %>%
  left_join(to_map %>% 
              sf::st_drop_geometry() %>% 
              select(GEOID, candidate, trump_margin)) %>%
  rename(Pres16 = candidate) %>%
  mutate(`116` = ifelse(GEOID %in% pa18_rs, 'Republican Party', `116`),
         `116` = ifelse(GEOID %in% pa18_ds, 'Democratic Party', `116`)) %>%  
  mutate(Pres16_House18 = paste0(Pres16, ' | ', `116`))

Democrats netted a total of 40 seats in the midterm elections in 2018. The numbers & districts presented below align with those presented on Bollotpedia.

house_flips1 %>%
  group_by(house_flip) %>%
  count() %>%
  knitr::kable()
house_flipn
Democratic Party | Democratic Party192
Democratic Party | Republican Party3
Republican Party | Democratic Party43
Republican Party | Republican Party197

House Representatives from flipped districts:

house_flips1 %>%
  filter(house_flip %in% 
           c('Democratic Party | Republican Party', 
             'Republican Party | Democratic Party')) %>%
  mutate(house_flip = ifelse(grepl('^D', house_flip), 'D -> R', 'R -> D')) %>%
  select(house_flip, state, district_code, house_rep) %>%
  DT::datatable(rownames = FALSE)

The 31 House Democrats in Trump-supportive districts

The table below summarizes how districts voted in the 2016 presidential election and House elections in 2018. Again, 31 House Democrats represent congressional districts that Trump won in 2016’s presidential election. In contrast, only three Republicans represent districts carried by HRC. Note: Numbers & districts align with those presented in this article from The Hill.

house_flips1 %>%
  group_by(Pres16_House18) %>%
  count() %>%
  #mutate(n = formattable::color_tile('white', 'steelblue')(n)) %>%
  knitr::kable()
Pres16_House18n
Clinton | Democratic Party202
Clinton | Republican Party3
Trump | Democratic Party31
Trump | Republican Party199

The 31 Democratic lawmakers representing Trump won districts include:

house_flips1 %>%
  filter(Pres16_House18 == 'Trump | Democratic Party') %>%
  select(state, district_code, house_rep) %>%
  DT::datatable(rownames = FALSE)

A quick geographical perspective

to_map2 <- uspoliticalextras::uspol_dkos_equalarea_sf$hex_cds %>%
  select(GEOID) %>%
  left_join(house_flips1, by = 'GEOID') 

to_map2 %>%
  ggplot() + 
  geom_sf(aes(fill = Pres16_House18),
          alpha = .75,
          color = 'white') +
  geom_sf(data=uspoliticalextras::uspol_dkos_equalarea_sf$hex_states, 
          fill = NA, 
          show.legend = F, 
          color="black", 
          lwd=.5) +
  ggsflabel::geom_sf_text(data = uspoliticalextras::uspol_dkos_equalarea_sf$hex_cds,
                          aes(label = district_code), 
                          size = 2,
                          color='black') +
  ggthemes::scale_fill_stata() +
  theme_minimal()+
  theme(axis.text.x=element_blank(),
        axis.text.y=element_blank(),
        axis.title.x=element_blank(),
        axis.title.y=element_blank(),
        legend.position = 'bottom') +
  labs(title = "2016 Presidential Support & 2018 House Representative",
       subtitle = 'By Congressional District')

The 13 House Democrats in solid Trump districts

Of the 31, 13 Democrats represent districts Trump carried by more than 6 points.

house_flips1 %>%
  filter(Pres16_House18 == 'Trump | Democratic Party' & trump_margin > 6) %>%
  select(state, district_code, house_rep, trump_margin, house_rep_margin) %>%
  arrange(desc(trump_margin)) %>%
  knitr::kable()
statedistrict_codehouse_reptrump_marginhouse_rep_margin
Minnesota7PETERSON, Collin Clark30.8-4.3
New York22BRINDISI, Anthony15.5-1.8
Oklahoma5HORN, Kendra13.4-1.4
South Carolina1CUNNINGHAM, Joe13.1-1.4
Maine2GOLDEN, Jared10.3-1.2
New Mexico2TORRES SMALL, Xochitl10.2-1.9
Pennsylvania17LAMB, Conor10.1-12.5
New York11ROSE, Max9.8-6.5
New York19DELGADO, Antonio6.8-5.2
Michigan8SLOTKIN, Elissa6.7-3.8
Utah4McADAMS, Ben6.7-0.3
Virginia7SPANBERGER, Abigail6.5-1.9
New Jersey3KIM, Andy6.2-1.3

Voting patterns in presidential elections

Counts of how districts voted in the last three presidential elections are presented below.

house_flips2 <- house_flips1 %>%
  left_join (pres %>% 
               group_by(GEOID) %>%
               summarize(pres_lineage = paste0(candidate, collapse = ' | ')) %>%
               ungroup())
house_flips2 %>%
  group_by(pres_lineage) %>%
  count() %>%
  knitr::kable()
pres_lineagen
McCain | Obama | Trump1
McCain | Romney | Clinton8
McCain | Romney | Trump184
Obama | Obama | Clinton190
Obama | Obama | Trump20
Obama | Romney | Clinton7
Obama | Romney | Trump25

Voting patterns for the 31 Trump-House Dem districts

12 out of the 31 Dem-Trump districts have voted for Republican presidential candidates in the last three elections, ie, McCain-Romney-Trump districts.

house_flips2 %>%
  filter(Pres16_House18 == 'Trump | Democratic Party') %>%
  group_by(pres_lineage) %>%
  count() %>%
  knitr::kable()
pres_lineagen
McCain | Obama | Trump1
McCain | Romney | Trump12
Obama | Obama | Trump14
Obama | Romney | Trump4

Representatives for these twelve districts are presented below.

house_flips2 %>%
  filter(Pres16_House18 == 'Trump | Democratic Party' & 
           pres_lineage == 'McCain | Romney | Trump') %>%
  select(state, district_code, house_rep) %>%
  knitr::kable()
statedistrict_codehouse_rep
Arizona1O’HALLERAN, Thomas C.
Georgia6McBATH, Lucy
Minnesota7PETERSON, Collin Clark
New Jersey5GOTTHEIMER, Josh S.
New Jersey11SHERRILL, Mikie
New Mexico2TORRES SMALL, Xochitl
New York22BRINDISI, Anthony
Oklahoma5HORN, Kendra
South Carolina1CUNNINGHAM, Joe
Utah4McADAMS, Ben
Virginia2LURIA, Elaine
Virginia7SPANBERGER, Abigail

The 5 House Democrats that should probably vote against impeachment

The table below lists the five House Reps representing districts that have supported Republican presidential candidates in the last three elections, with 2016 Trump margins greater than ten points.

house_flips2 %>%
  filter(Pres16_House18 == 'Trump | Democratic Party' & 
           trump_margin > 10 &
           pres_lineage == 'McCain | Romney | Trump') %>%
  select(state, district_code, house_rep, pres_lineage, trump_margin) %>%
  arrange(desc(trump_margin)) %>%
  knitr::kable()
statedistrict_codehouse_reppres_lineagetrump_margin
Minnesota7PETERSON, Collin ClarkMcCain | Romney | Trump30.8
New York22BRINDISI, AnthonyMcCain | Romney | Trump15.5
Oklahoma5HORN, KendraMcCain | Romney | Trump13.4
South Carolina1CUNNINGHAM, JoeMcCain | Romney | Trump13.1
New Mexico2TORRES SMALL, XochitlMcCain | Romney | Trump10.2

Front-line Freshmen House Democrats

Via the Rvoteview package, we identify 88 freshman House Representatives, 56 of which are Democrats.

house_vv_freshies <- Rvoteview:: member_search(chamber= 'House', congress = 116) %>%
  filter(congresses == 'c(116, 116)' & party_name != 'Independent') %>%
  select(bioname, party_name) %>%
  rename(house_rep = bioname) 

house_vv_freshies %>%
  group_by(party_name) %>%
  count() %>%
  knitr::kable()
party_namen
Democratic Party56
Republican Party32

Of the 31, then, 22 are freshman. So, a pretty vulnerable group.

house_flips3 <- house_flips2 %>%
  left_join(house_vv_freshies %>% 
              mutate(is_fresh = 'Freshman') %>% 
              select(house_rep, is_fresh)) %>%
  mutate(is_fresh = ifelse(is.na(is_fresh), 'Not', is_fresh))

house_flips3 %>%
  group_by(is_fresh, Pres16_House18) %>%
  count() %>%
  #filter(is_fresh == 'Y') %>%
  spread(is_fresh, n) %>%
  janitor::adorn_totals(where = c('row', 'col')) %>%
  knitr::kable()
Pres16_House18FreshmanNotTotal
Clinton | Democratic Party35167202
Clinton | Republican PartyNA33
Trump | Democratic Party22931
Trump | Republican Party29170199
Total86349435

Data set

The data set compiled in this post/guide is available here.

To leave a comment for the author, please follow the link and comment on their blog: Jason Timm.

R-bloggers.com offers daily e-mail updates about R news and tutorials about learning R and many other topics. Click here if you're looking to post or find an R/data-science job.
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.

Never miss an update!
Subscribe to R-bloggers to receive
e-mails with the latest R posts.
(You will not see this message again.)

Click here to close (This popup will not appear again)