rggplot2colorbrewer

Indicating direction of change in a dumbbell plot using arrows and colors in ggplot2


I have the following dataset:

enter image description here

Output of dput(prob_metrics) is:

structure(list(round = c("baseline", "baseline", "baseline", 
"baseline", "baseline", "baseline", "baseline", "baseline", "baseline", 
"endline", "endline", "endline", "endline", "endline", "endline", 
"endline", "endline", "endline"), metric = structure(c(1L, 2L, 
3L, 4L, 5L, 6L, 7L, 8L, 9L, 1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L
), levels = c("Kesehatan yang buruk", "Konflik keluarga", "Tingkatan penghasilan", 
"Kekerasan dalam Rumah Tangga", "Kenakalan", "Kurangnya kepercayaan atau respek", 
"Rendahnya Kerjasama Masyarakat", "Kurangnya keamanan", "Kekurangan ada pendampingan"
), class = "factor"), percentage = c(82.1, 82.6, 77.7, 80.6, 
78.1, 81.2, 78.2, 66.2, 75.9, 62.3, 70.9, 76.2, 82.8, 98.4, 96.5, 
95.8, 95.1, 79), bump_percentage = c(80.1, 80.6, 75.7, 78.6, 
76.1, 79.2, 76.2, 64.2, 73.9, 64.3, 72.9, 78.2, 84.8, 100.4, 
98.5, 97.8, 97.1, 81), midpoint = c(72.2, 76.75, 76.95, 81.7, 
88.25, 88.85, 87, 80.65, 77.45, 72.2, 76.75, 76.95, 81.7, 88.25, 
88.85, 87, 80.65, 77.45)), row.names = c(NA, -18L), class = c("tbl_df", 
"tbl", "data.frame"))

I have created this plot

enter image description here

using this code:

mh_theme <-theme(panel.background = element_rect(fill = "#F2E6CE"),
                 plot.background = element_rect(fill = "#F2E6CE"),
                 legend.background = element_rect(fill = "#F2E6CE"),
                 panel.grid.major = element_line(color = "#DCD1BC"),
                 legend.title = element_blank())
ggplot(prob_metrics, aes(x=percentage, y=metric)) + 
  geom_line(color="gray", size=1.75) +
  geom_segment(aes(x = midpoint, xend = midpoint + 1, yend = metric), 
               arrow = arrow(angle = 30, length = unit(.15, "inches"), type = "closed"), 
               color = "gray", ) +
  geom_point(size=2) + 
  geom_text(aes(label=glue("{percentage}%"), x=percentage), 
            color = "dimgray", size=3, nudge_y = .2) +
  theme_fivethirtyeight() + mh_theme + xlim(50,102) + 
  labs(title = str_wrap("Persentase anak dengan status gizi buruk yang sehat", 38)) +
  scale_y_discrete(labels = function(x) str_wrap(x, width = 20))

Now here is my problem: up until this plot, the endline value has always been bigger than the baseline value of every single variable in my analysis. Now, I have some values that decrease from baseline to endline. To visualize this, I want to do two things that are giving me a surprising amount of trouble:

  1. I want to color the baseline points with the hex code "#3C4C56" and the endline with "#DB5628". I know how to color the points by round in theory, and I've done it successfully here using Rcolorbrewer, but I can only get it to work using their remade palettes. I tried:
base_end_colors <- as.character(c("baseline"="#3C4C56", "endline" = "#DB5628"))
base_end_scale <- scale_color_manual(name="round", values = base_end_colors)

and then my_plot + base_end_scale but that didn't work. So problem #1 is coloring the points those two colors based on the round variable.

  1. I would also like the arrows to point from baseline to endline, rather than simply pointing to the right, like they do right now. My geom_segment trick for plotting the arrows was, I knew when I coded it, not particularly strong or flexible. Now its met its limit. How could I most simply get these arrows to point from baseline to endline.

Solution

  • Your color issue is easily fixed by mapping on the color aes and setting your desired colors via scale_color_manual. To fix the direction of your arrows you could first filter the data for the baseline values in geom_segement (Otherwise your are drawing the arrows two times) and use and ifelse or the sign function as I do below to "set" the direction of the segment and the arrow.

    library(ggplot2)
    library(ggthemes)
    library(stringr)
    library(glue)
    
    ggplot(prob_metrics, aes(x=percentage, y=metric)) + 
      geom_line(color="gray", size=1.75) +
      geom_segment(data = ~subset(.x, round == "baseline"), 
                   aes(
        x = midpoint,
        xend = midpoint + .5 * sign(midpoint - percentage), 
        yend = metric), 
        arrow = arrow(angle = 30, length = unit(.15, "inches"), type = "closed"), 
        color = "gray") +
      geom_point(aes(color = round), size= 2) + 
      geom_text(aes(label=glue("{percentage}%"), x=percentage), 
                color = "dimgray", size=3, nudge_y = .2) +
      theme_fivethirtyeight() + mh_theme + xlim(50,102) + 
      labs(title = str_wrap("Persentase anak dengan status gizi buruk yang sehat", 38)) +
      scale_y_discrete(labels = function(x) str_wrap(x, width = 20)) +
      scale_color_manual(values = c(baseline = "#3C4C56", endline = "#DB5628")) +
      theme(legend.key = element_rect(fill = NA))
    

    enter image description here