How to make a dumbell plot with ggplot2? Not plotting correctly R

Viewed 57

I'm trying to make a dumbell plot in ggplot. This is a graph I am trying to recreate in ggplot that I originally made in Tableau.

Although something is wrong with my code - I am trying to follow this tutorial but my data is not being paired properly. enter link description here

Here is my code

gnatt <- structure(list(Month = c("JAN 2020", "FEB 2020", "MAR 2020", 
                                  "APR 2020", "MAY 2020", "JUN 2020", "JUL 2020", "AUG 2020", "SEP 2020", 
                                  "OCT 2020", "NOV 2020", "DEC 2020", "JAN 2021", "FEB 2021", "MAR 2021", 
                                  "APR 2021", "MAY 2021", "JUN 2021", "JUL 2021", "JAN 2020", "FEB 2020", 
                                  "MAR 2020", "APR 2020", "MAY 2020", "JUN 2020", "JUL 2020", "AUG 2020", 
                                  "SEP 2020", "OCT 2020", "NOV 2020", "DEC 2020", "JAN 2021", "FEB 2021", 
                                  "MAR 2021", "APR 2021", "MAY 2021", "JUN 2021", "JUL 2021"), 
                        Outcome = c("Additions to Waitlist", "Additions to Waitlist", 
                                    "Additions to Waitlist", "Additions to Waitlist", "Additions to Waitlist", 
                                    "Additions to Waitlist", "Additions to Waitlist", "Additions to Waitlist", 
                                    "Additions to Waitlist", "Additions to Waitlist", "Additions to Waitlist", 
                                    "Additions to Waitlist", "Additions to Waitlist", "Additions to Waitlist", 
                                    "Additions to Waitlist", "Additions to Waitlist", "Additions to Waitlist", 
                                    "Additions to Waitlist", "Additions to Waitlist", "Total Assessments", 
                                    "Total Assessments", "Total Assessments", "Total Assessments", 
                                    "Total Assessments", "Total Assessments", "Total Assessments", 
                                    "Total Assessments", "Total Assessments", "Total Assessments", 
                                    "Total Assessments", "Total Assessments", "Total Assessments", 
                                    "Total Assessments", "Total Assessments", "Total Assessments", 
                                    "Total Assessments", "Total Assessments", "Total Assessments"
                        ), Count = c(222, 199, 160, 30, 98, 127, 75, 121, 164, 140, 
                                     108, 176, 158, 181, 278, 299, 275, 385, 517, 390, 376, 317, 
                                     75, 146, 211, 140, 198, 271, 368, 290, 397, 375, 363, 524, 
                                     441, 509, 697, 961), Percent = c(0.569230769230769, 0.529255319148936, 
                                                                      0.504731861198738, 0.4, 0.671232876712329, 0.601895734597156, 
                                                                      0.535714285714286, 0.611111111111111, 0.605166051660517, 
                                                                      0.380434782608696, 0.372413793103448, 0.443324937027708, 
                                                                      0.421333333333333, 0.49862258953168, 0.530534351145038, 0.678004535147392, 
                                                                      0.54, 0.55, 0.54, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 
                                                                      NA, NA, NA, NA, NA, NA, NA, NA, NA)), row.names = c(NA, -38L
                                                                      ), class = c("tbl_df", "tbl", "data.frame"))

gnatt <- gnatt %>% 
  mutate(paired = rep(1:(n()/2),each=2),
         Month=factor(Month))

gnatt %>% 
  ggplot(aes(x=Month, y=Count)) + 
  geom_line(aes(group=paired)) + 
    geom_point(aes(color=Outcome), size = 4) + 
    theme(legend.position = "top")

This is the output I am getting.

enter image description here

My desires output would be something like this.

enter image description here

2 Answers

You should use Month as the grouping variable:

gnatt %>% 
    ggplot(aes(x = Month, y = Count)) + 
    geom_line(aes(group = Month)) + # Note group here
    geom_point(aes(color = Outcome), size = 4) + 
    theme(legend.position = "top")

And to make it even more like the example, you can do the following:

gnatt %>% 
    ggplot(aes(x = Month, y = Count)) + 
    geom_line(aes(group = Month), size = 4, color = "#cccccc") + 
    geom_point(aes(color = Outcome), size = 4) + 
    scale_color_manual(values = c("red", "blue")) + ## Custom colors
    theme_minimal() +
    theme(legend.position = "top") 

Just tried to reproduce it as close as I can:

library(tidyverse)

dat <- dat |>
  rename_with(tolower) |>
  mutate(
    date  = as.Date(
      gsub(
        '(\\w{3})\\s(\\d{4})', 
        '\\1 01 \\2', 
        stringr::str_to_sentence(month)
      ),
      '%b %d %Y'
    ),
    percent = ifelse(
        !is.na(percent), 
        sprintf('(%d %s)', round(percent * 100), '%'),
        NA_character_
    ), 
    month   = NULL
  ) 

sgm <- pivot_wider(
  dat, 
  id_cols     = date, 
  names_from  = 'outcome', 
  values_from = 'count'
  ) |>
  setNames(c('date', 'y', 'yend'))

ggplot(data = sgm) +
  geom_segment(
    aes(x = date, xend = date, y = y, yend = yend), 
    size = 7, 
    colour = 'grey90'
    ) +
  geom_point(
    data    = dat, 
    mapping = aes(x = date, y = count, colour = outcome), 
    size    = 7
    ) + 
  geom_text(
    mapping = aes(x = date, y = y, label = y), 
    nudge_y = -30, 
    size    = 3.5
    ) +
  geom_text(
    mapping = aes(x = date, y = yend, label = yend), 
    nudge_y = 30, 
    size    = 3.5
    ) +
  geom_text(
    data    = dat, 
    mapping = aes(x = date, y = count, label = percent), 
    nudge_y = -55, size = 3.5, colour = 'gray50'
    ) +
  scale_x_date(date_breaks = '1 month', date_labels = '%b %y') +
  scale_y_continuous(breaks = seq(0, 1000, by = 50)) +
  scale_color_manual(values = c('skyblue', 'coral')) +
  ggthemes::theme_clean() +
  theme(
    legend.position   = 'bottom',
    legend.title      = element_blank(), 
    legend.background = element_blank(),
    axis.title.x      = element_blank(),
    axis.title.y      = element_blank(),
    axis.line.x       = element_line(colour = 'gray50'),
    axis.line.y       = element_line(colour = 'gray50'),
    axis.ticks        = element_line(colour = 'gray50'), 
    axis.text         = element_text(colour = 'gray50')
  )

desired graphical output

Related