I. Introduction

The purpose of this post is to explore the voting records of Senators Barbara Boxer and Diane Feinstein.


II. The Sunlight Foundation

The Sunlight Foundation is a nonpartisan, nonprofit organization that uses the tools of civic tech, open data, policy analysis, and journalism to make government and politics more accountable and transparent. They have several APIs available, and we’ll use a few to learn about our elected officials. You’ll need to obtain an API key first, and you can do so here.


III. Senate Voting Records

Let’s say we’re interested in the voting records of California’s senators, Diane Feinstein and Barbara Boxer. Unfortunately, the Congress API only has data going back to 2009, but that’s still a seven year period to observe.

Before we can access their voting records, we need to obtain their legislative ids. These are identifiers that appear throughout the API.

library(jsonlite)
library(httr)
library(dplyr)

apikey <- "xxxkeyxxx"
res <- GET("https://congress.api.sunlightfoundation.com",
           path = "legislators/locate",
           query = list(zip = "94087",
                        apikey = apikey)) %>% 
  content(type = "text") %>% 
  fromJSON(flatten = TRUE)
leg_ids <- res$results %>% 
  filter(chamber == "senate") %>%
  .$bioguide_id
leg_ids
## [1] "B000711" "F000062"

Boxer’s id is B000711 and Feinstein’s is F000062.

Now that we have the ids, let’s make another API to obtain their respective voting records. In brief, I’m (1) specifying the precise fields I want returned; (2) creating a vector of years to loop through; (3) for every year between 2009-2016, looping through the API and extracting the senators voting record for that year; and (4) binding all the years together into a table called votes.

fields <- "bill_id,question,voters.vote,voters,year"
years <- as.character(2009:2016)
ca_sen_list <- list()
for (i in 1:length(years)) {
  sen <- GET("https://congress.api.sunlightfoundation.com",
             path = "votes",
             query = list(chamber = "senate",
                          fields = fields,
                          year = years[i],
                          apikey = apikey)) %>% 
    content(type = "text") %>% 
    fromJSON(flatten = TRUE)
  sen_df <- sen[[1]]
  sen_df <- sen_df %>% 
    select(question, bill_id, year, voters.B000711.vote, voters.F000062.vote)
  ca_sen_list[[i]] <- sen_df
}
votes <- bind_rows(ca_sen_list)

Let’s glance at our votes table:

question bill_id year voters.B000711.vote voters.F000062.vote
On the Cloture Motion S. 22 s22-111 2009 Yea Yea
On the Cloture Motion S. 22 s22-111 2009 Yea Yea
On Passage of the Bill S. 22 s22-111 2009 Yea Yea
On the Cloture Motion S. 181 s181-111 2009 Yea Yea
On the Joint Resolution S.J.Res. 5 sjres5-111 2009 Nay Nay
On the Nomination PN64-1 NA 2009 Yea Yea

Now let’s answer some questions.

1. How many times did Boxer and Fienstein cast opposing votes?

votes %>% 
  filter(voters.B000711.vote != voters.F000062.vote & 
           voters.B000711.vote != "Not Voting" & 
           voters.F000062.vote != "Not Voting") %>% 
  kable()
question bill_id year voters.B000711.vote voters.F000062.vote
On the Amendment S.Amdt. 3301 to S.Amdt. 3299 to H.J.Res. 45 (No short title on file) hjres45-111 2010 Nay Yea
On the Nomination PN959 NA 2010 Nay Yea
On the Amendment S.Amdt. 1500 to S.Amdt. 1470 to S. 2038 (Stop Trading on Congressional Knowledge Act of 2012) s2038-112 2012 Yea Nay
On the Amendment S.Amdt. 1493 to S.Amdt. 1470 to S. 2038 (Stop Trading on Congressional Knowledge Act of 2012) s2038-112 2012 Nay Yea
On the Amendment S.Amdt. 3871 to S.Amdt. 3801 to H.R. 2028 (Energy and Water Development and Related Agencies Appropriations Act, 2016) hr2028-114 2016 Yea Nay
On the Amendment S.Amdt. 3812 to S.Amdt. 3801 to H.R. 2028 (Energy and Water Development and Related Agencies Appropriations Act, 2016) hr2028-114 2016 Yea Nay

It’s only happened six times in the past seven years:

vote_plot <- votes %>% 
  mutate(vote_cast = ifelse(voters.B000711.vote != voters.F000062.vote & voters.B000711.vote != "Not Voting" & voters.F000062.vote != "Not Voting", "Opposing Vote", "Same Vote"))

ggplot(vote_plot, aes(vote_cast)) +
  geom_bar(stat = "count", fill = "lightgreen", color = "black", width = 0.5) +
  annotate("text", x = 2, y = 158, label = "153 votes", color = "black") +
  annotate("text", x = 1, y = 12, label = "6 votes", color = "black") +
  labs(x = "", y = "") +
  ggtitle("Senator Boxer and Senator Fienstein's \nVoting Records, 2009-2016") +
  theme_minimal()


2. How many times have either Senator Boxer or Senator Fienstein voted for a bill sponsored by a Republican colleague?

This is going to take a few steps. First, let’s get the ids for every Republican senator:

req <- GET("https://congress.api.sunlightfoundation.com",
            path = "legislators",
            query = list(chamber = "senate",
                         party = "R",
                         apikey = apikey)) %>%
  content(type = "text") %>% 
  fromJSON(flatten = TRUE)

rep_ids <- req$results %>%
  .$bioguide_id
rep_ids
##  [1] "S001197" "R000605" "T000476" "E000295" "P000612" "S001198" "C001098"
##  [8] "F000463" "D000618" "C001095" "H001041" "V000127" "T000461" "T000250"
## [15] "S000320" "S001184" "R000595" "P000449" "P000603" "M001153"

Second, let’s get every bill_id that’s been sponsored by a Republican senator:

republican_bill_ids <- c()
for (i in 1:length(rep_ids)) {
  req <- GET("https://congress.api.sunlightfoundation.com",
             path = "bills",
             query = list(chamber = "senate",
                          sponsor_id = rep_ids[i],
                          apikey = apikey)) %>% 
    content(type = "text") %>% 
    fromJSON(flatten = TRUE)
  republican_bill_ids <- append(republican_bill_ids, req$results$bill_id)
}
head(republican_bill_ids)
## [1] "s2849-114"     "s2803-114"     "sconres33-114" "s2128-114"    
## [5] "s2066-114"     "s748-114"

Finally, let’s see how many times and to which bills Boxer or Feinstein voted “Yea”. Good thing we thought ahead and already stashed the bill_id in one of our earlier calls:

votes %>%
  filter(bill_id %in% republican_bill_ids, 
         voters.B000711.vote == "Yea" | voters.F000062.vote == "Yea") %>%
  kable()
question bill_id year voters.B000711.vote voters.F000062.vote
On Passage of the Bill S. 2012 s2012-114 2016 Yea Yea
On the Amendment S.Amdt. 3312 to S.Amdt. 2953 to S. 2012 (Energy Policy Modernization Act of 2015) s2012-114 2016 Yea Yea

The two senators voted for a Republican-sponsored bill only four times, and it was three amendments to the same bill. Before we wrap up, let’s take a look at the Energy Policy Modernization Act of 2015.

rep_bill <- GET("https://congress.api.sunlightfoundation.com",
                path = "bills/search",
                query = list(bill_id = "s2012-114",
                             apikey = apikey)) %>% 
  content(type = "text") %>% 
  fromJSON(flatten = TRUE)

rep_bill[[1]] %>% 
  select(official_title, history.senate_passage_result, history.enacted) %>% 
  kable()
official_title history.senate_passage_result history.enacted
An original bill to provide for the modernization of the energy policy of the United States, and for other purposes. pass FALSE

Looks like the bill passed the senate, but it has yet to be enacted.