Search code examples
rggplot2

Combine stacked bar chart with line chart (ideally with dual Y axes)


I have a sample data:

name <- rep(c("ba", "EW", "RW", "Se", "St", "US", "VN"), 2)

value <-  c(0, 6323, 7397, 13945, 11801, 55255, 22519, 4124, 13540, 9616, 57724, 6646, 22021, 8841)

type <- c(rep("g", 7), rep("o", 7))

test <- data.frame(name, value, type)

and have created a stacked bar chart using

library(ggplot2)

ggplot(test, aes(x = name, y = value, fill = type)) +
  geom_bar(position = position_stack(reverse = TRUE), stat = "identity") +
  theme(plot.title = element_text(hjust = 0.5)) +
  scale_fill_manual(values = c("#0099f9", "#69c6ff")) +
  geom_text(aes(label = value),
    position = position_stack(vjust = 0.5, reverse = TRUE),
    colour = "black", size = 3
  ) +
  guides(fill = guide_legend(title = "", reverse = TRUE))

Now I want to add another line to the chart using data:

name2 <- c("ba", "EW", "RW", "Se", "St", "US", "VN") 
share <- c("100%", "61%", "47%", "80%", "34%", "28%", "28%") 
test2 <- data.frame(name2, share)

So basically they use the same x axis and the share is the percentage from type o / (type g + type o) and the data label should also be shown.

I've seen the long discussion whether dual axes makes sense https://www.perceptualedge.com/articles/visual_business_intelligence/dual-scaled_axes.pdf but I just need to have it, how can I do this? Either use ggplot2 or not, this doesn't matter, I just want the chart.

Editted/added with one more question: How can I change the line type into line with markers (like the one in Excel) and add data label? I already have data label specified in geom_text for the bars but I also want label for the line


Solution

  • You need to specify a secondary axis via the sec.axis argument in scale_y_continuous and provide a proper scaling factor. Furthermore, you should provide your percentages as values and not as text like this:

    name2 <- c("ba", "EW", "RW", "Se", "St", "US", "VN") 
    share <- c(1, .61, .47, .8, .34, .28, .28) 
    test2 <- data.frame(name2, share)
    
    scaling_factor <- 8e4
    your_plot +
      geom_line(data = test2, 
                aes(x = name2, y = share * scaling_factor, fill = NULL, group = 1)) +
      scale_y_continuous(sec.axis = sec_axis(transform = ~ . / scaling_factor, 
                         labels = scales::percent))
    

    yields

    A stacked barchart with a line added and a secondary y-axis showing percentages