This article provides an example of using
geom_braid() with a flipped set of aesthetics
xmax instead of the usual
ymax. This change is primarily motivated by the fact that we are visualizing judicial ideology scores, from strongly liberal to strongly conservative, and we are accustomed to interpreting ideologies on the left-right political spectrum.
How has the ideology of the US Supreme Court changed over time?
A common way to measure judicial ideology is to use Martin-Quinn scores.
Developed by political science researchers Andrew Martin and Kevin Quinn in 2002, a Martin-Quinn score is a summary of a justice’s voting record in a given year using a Bayesian model. Positive scores indicate a conservative ideology, negative scores indicate a liberal ideology. The further a score is from zero, the stronger the ideology.
In this article, we’ll work with a couple datasets that Martin and Quinn maintain at mqscores.lsa.umich.edu.
We’ll start with
court.csv, which provides the Martin-Quinn score of a hypothetical “median justice” each year since 1937.
library(ggplot2) library(ggbraid) library(readr) library(dplyr) <- read_csv( court "https://mqscores.lsa.umich.edu/media/2020/court.csv", col_types = cols_only(term = col_character(), med = col_double()) %>% ) mutate(year = as.integer(substr(term, 1, 4))) %>% group_by(year) %>% summarize(mqscore = median(med), .groups = "drop") %>% arrange(desc(year)) court#> # A tibble: 84 × 2 #> year mqscore #> <int> <dbl> #> 1 2020 0.607 #> 2 2019 0.303 #> 3 2018 0.371 #> 4 2017 0.293 #> 5 2016 -0.058 #> 6 2015 -0.272 #> 7 2014 -0.224 #> 8 2013 0.066 #> 9 2012 0.244 #> 10 2011 0.302 #> # … with 74 more rows
Let’s plot the data in
court by mapping
y, and applying the line geometry with
geom_line(). Also, place a horizontal line at
yintercept = 0 with
geom_hline() to better identify the point at which an ideology
ggplot(court, aes(x = year, y = mqscore)) + geom_line() + geom_hline(yintercept = 0)
A nice, simple plot.
Another way to convey this relationship is to instead map
y. With this mapping, Martin-Quinn scores that indicate a conservative ideology are to the right of zero and scores that indicate a liberal ideology are to the left. This matches the left-right political spectrum that we are accustomed to, although it does put a temporal variable on the y axis which can feel strange.
In any case, let’s give it a try.
Starting with the previous code, switch
mqscore, and replace
yintercept = 0 with
xintercept = 0.
ggplot(court, aes(x = mqscore, y = year)) + geom_line() + geom_vline(xintercept = 0)
Hmmm, that isn’t right. What’s gone wrong?
The problem is that
geom_line() connects observations in the order of the variable on the x axis. So, because we have mapped
geom_line() orders the data by
mqscore before drawing lines between observations. That’s not what we want, we’d rather the geom leave the order as is.
To avoid this ordering behavior, we can use
geom_path() in place of
ggplot(court, aes(x = mqscore, y = year)) + geom_path() + geom_vline(xintercept = 0)
But this plot could really use some color. We can use
geom_braid() to fill the area between the “median justice” Martin-Quinn score line and the x intercept at 0.
ggplot(court, aes(x = mqscore, y = year)) + geom_path() + geom_vline(xintercept = 0) + geom_braid( aes(xmin = mqscore, xmax = 0, fill = mqscore < 0), method = "line" )
Touching this up a bit, we can remove the vertical line at zero because it is no longer necessary, and we can remove the
fill aesthetic legend because it doesn’t add any value. While we’re at it, let’s change the colors and add some transparency.
ggplot(court, aes(x = mqscore, y = year)) + geom_path() + geom_braid( aes(xmin = mqscore, xmax = 0, fill = mqscore < 0), method = "line", alpha = 0.3 + ) scale_fill_manual(values = c("red", "blue")) + guides(fill = "none")
Now it may also be valuable to include data from
justices.csv, which provides the Martin-Quinn score of every justice each year since 1937.
<- read_csv( justices "https://mqscores.lsa.umich.edu/media/2020/justices.csv", col_types = cols_only( term = col_integer(), justiceName = col_character(), post_med = col_double() )%>% ) rename(year = term, name = justiceName, mqscore = post_med) %>% arrange(desc(year), name) justices#> # A tibble: 764 × 3 #> year name mqscore #> <int> <chr> <dbl> #> 1 2020 ACBarrett 0.981 #> 2 2020 BMKavanaugh 0.539 #> 3 2020 CThomas 3 #> 4 2020 EKagan -1.49 #> 5 2020 JGRoberts 0.498 #> 6 2020 NMGorsuch 1.1 #> 7 2020 SAAlito 2.15 #> 8 2020 SGBreyer -1.89 #> 9 2020 SSotomayor -3.94 #> 10 2019 BMKavanaugh 0.552 #> # … with 754 more rows
Let’s add individual Martin-Quinn score lines for every justice.
ggplot(court, aes(x = mqscore, y = year)) + geom_path() + geom_braid( aes(xmin = mqscore, xmax = 0, fill = mqscore < 0), method = "line", alpha = 0.3 + ) geom_path(aes(group = name), data = justices, size = 0.3, alpha = 0.2) + scale_fill_manual(values = c("red", "blue")) + guides(fill = "none")