Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dodged dumbbell plots with ggplot2

Tags:

r

ggplot2

This question is based on this prior question.

Consider the following plot:

Domain = c("A", "B", "C", "D", "E", "F", "G", 
           "A", "B", "C", "D", "E", "F", "G", "A", "B", "C", "D", "E", "F", 
           "G", "A", "B", "C", "D", "E", "F", "G") 

Area = c("State", "State", 
         "State", "State", "State", "State", "State", "National", "National", 
         "National", "National", "National", "National", "National", "State", 
         "State", "State", "State", "State", "State", "State", "National", 
         "National", "National", "National", "National", "National", "National")

race = c("White", "White", "White", "White", "White", "White", 
         "White", "White", "White", "White", "White", "White", "White", 
         "White", "Black", "Black", "Black", "Black", "Black", "Black", 
         "Black", "Black", "Black", "Black", "Black", "Black", "Black", 
         "Black") 

pct_agreement = c(0.557610213756561, 0.735042750835419, 
                  0.567375898361206, 0.633762538433075, 0.64091557264328, 0.750356614589691, 
                  0.564539015293121, 0.651861846446991, 0.697574973106384, 0.653521358966827, 
                  0.713940441608429, 0.680985689163208, 0.751584351062775, 0.642535984516144, 
                  0.488484561443329, 0.581625580787659, 0.456939995288849, 0.580652594566345, 
                  0.630399644374847, 0.711643815040588, 0.347775995731354, 0.627996683120728, 
                  0.668737232685089, 0.610245823860168, 0.690373718738556, 0.705771028995514, 
                  0.738830924034119, 0.550933301448822)

df <- data.frame(Domain, Area, race, pct_agreement)

library(tidyverse)

ggplot(df) +
  geom_point(
    aes(
      x = Domain, y = pct_agreement, color = Area, shape = race,
      group = Area
    ), 
    position = position_dodge(width = 1)
  ) +
  coord_flip()

Now we want to turn it into a dumbbell plot by connecting each pair of points of the same domain and area. The obvious code would be the following:

df2 <- pivot_wider(df, names_from = race, values_from = pct_agreement)

ggplot(df) +
  geom_point(
    aes(
      x = Domain, y = pct_agreement, color = Area, shape = race,
      group = Area
    ), 
    position = position_dodge(width = 1)
  ) +
  geom_segment(
    data = df2,
    aes(
      x = Domain, xend = Domain, y = White, yend = Black,
      color = Area
    ),
    position = position_dodge(width = 1)
  ) +
  coord_flip()

Created on 2019-11-08 by the reprex package (v0.3.0)

Yet, clearly, that didn't work, because position_dodge() didn't dodge the xend aesthetic. I consider this a bug in ggplot2 that probably should be fixed. However, in the mean time, what's the easiest way of making this plot? I can think of various ways to do it but they all seem cumbersome. Am I missing something?

like image 512
Claus Wilke Avatar asked Nov 08 '19 06:11

Claus Wilke


Video Answer


1 Answers

I find nested groupings can often lead to difficulties with specific plots. In these situations I found the interaction() function to be very helpful since it allows for concise code and avoiding the data reformatting. We can define a new grouping for the line segments.

Importantly, the following solution works with position dodging because it uses geom_line() instead of geom_segment(). This avoids the xend aesthetic which position_dodge() can't handle.

ggplot(df) +
  geom_point(
    aes(
      x = Domain, y = pct_agreement, color = Area,
      shape = race, group = Area
    ), 
    position = position_dodge(width = 0.5)
  ) +
  geom_line(
    aes(
      x = Domain, y = pct_agreement, color = Area, 
      group = interaction(Area, Domain)
    ),
    position = position_dodge(width = 0.5)
  ) +
  coord_flip()

enter image description here

like image 187
Mojoesque Avatar answered Nov 14 '22 21:11

Mojoesque