Search code examples
rggplot2geom-barstacked-chartgeom-col

Change the opacity on a fraction of each stacked geom_bar


Using the following data frame I aim to stack all x values by group using geom_bar or geom_col and fill them by subgroup.

 dat <- data.frame(group = c(rep("H", 4), rep("T",4)), subgroup = rep(c("A", "B", "C", "D"), 2),
               x = c(100, 10, 80, 50, 40, 50, 80, 70),
               y = c(20, 5, 50, 20, 20, 10, 40, 50))

But I also want to fill each stacked x value with their corresponding y value. However when I use the following code I get the following bar plot.

 dat %>%
   ggplot(aes(x = group, y = x, fill = subgroup)) +
   geom_col(alpha = .5) +
   geom_col(aes(x = group, y = y, fill = subgroup), alpha = 1)

Bar plot of x values by group stack filled by subgroup

Can anyone help me to fill a fraction of each subgroup with the y values please? All I have been able to get is an overlapped stack of y values, but not mapped to each color.

I have tried grouping the values and adding a key. however I am stuck with the previous plot


Solution

  • You will need to use geom_rect for this.

    If I may put in my 2 cents worth: The result is a fairly clattered visual. I think there might be other options out there to show your fractions. I think my favoured way would to use facets. This is not only making the fraction idea much clearer, and way more intuitive, but is also way simpler to code. See below

    library(tidyverse)
    dat <- data.frame(group = c(rep("H", 4), rep("T",4)), subgroup = rep(c("A", "B", "C", "D"), 2),
                      x = c(100, 10, 80, 50, 40, 50, 80, 70),
                      y = c(20, 5, 50, 20, 20, 10, 40, 50))
    ## width for rects
    w <- .45
    dat %>%
      ## because it is stacking in reverse alphbetic order
      arrange(group, desc(subgroup)) %>%
      group_by(group) %>%
      mutate(frac_ymin = lag(cumsum(x), default = 0), 
             frac_ymax = frac_ymin + y, 
             ## group needs to be numeric for geom_rect
             group = as.integer(factor(group, levels = c("H", "T")))) %>%
      ggplot(aes(x = group, y = x, fill = subgroup)) +
      geom_col(alpha = .5) +
    ## now use geom_rect instead
      geom_rect(aes(xmin = group - w, xmax = group + w, 
                   ymin = frac_ymin, ymax = frac_ymax, 
                   fill = subgroup), alpha = 1)
    

    Suggestion to use facets instead

    library(tidyverse)
    dat <- data.frame(group = c(rep("H", 4), rep("T",4)), subgroup = rep(c("A", "B", "C", "D"), 2),
                      x = c(100, 10, 80, 50, 40, 50, 80, 70),
                      y = c(20, 5, 50, 20, 20, 10, 40, 50))
    
    ## you can use your old code, just add a facet!
    dat %>%
      ggplot(aes(x = group, y = x, fill = subgroup)) +
      geom_col(alpha = .5) +
      geom_col(aes(x = group, y = y, fill = subgroup), alpha = 1) +
      facet_wrap(~subgroup)