rggplot2colorsgeom-barggpattern

Fill and color manual a geom_bar_pattern


I have count data from several samples, which map to two classes, two groups, and three types:

library(dplyr)
set.seed(1)
df <- data.frame(type = c(rep("A",12), rep("B",12), rep("C",12)),
                 group = rep(c("O1","O1","O2","O2","O3","O3","Y1","Y1","Y2","Y2","Y3","Y3"),3),
                 class = rep(c("c1","c2"),18),
                 sample = rep(c("O1.c1_1","O1.c2_1","O2.c1_1","O2.c2_1","O3.c1_1","O3.c2_1",
                                "Y1.c1_1","Y1.c2_1","Y2.c1_1","Y2.c2_1","Y3.c1_1","Y3.c2_1"),3),
                 n = round(runif(36,10,50))) %>%
  dplyr::group_by(type) %>% dplyr::mutate(type.n = sum(n)) %>%
  dplyr::ungroup() %>% dplyr::mutate(f = n/type.n)
df$sample <- factor(df$sample, levels = c("O1.c1_1","O1.c2_1","O2.c1_1","O2.c2_1","O3.c1_1","O3.c2_1","Y1.c1_1","Y1.c2_1","Y2.c1_1","Y2.c2_1","Y3.c1_1","Y3.c2_1"))
df$class <- factor(df$class, levels = c("c1","c2"))

Each sample encodes in its name the class and group it was sampled from (for example, these might be single-cell RNA-seq samples, where class corresponds to a tissue, group corresponds to an animal, and type corresponds to a cell type).

I'd like to plot the samples' df$f values as a stacked bar plot, where each bar is type, color-coded by group, and pattern-coded by class, and I'd like to manually specify both the group (bar sector) colors as well as the pattern colors.

Here's a data.frame for that:

colors.df <- data.frame(group = levels(df$group),color = c("#55a189","#d27551","#7585a9","#ffa5ea","#c7ff64","#ffff38"))

I'm trying ggpattern for that using this code:

library(ggplot2)
library(ggpattern)
ggplot(df, aes(type,f, fill = group))+
  geom_bar_pattern(colour="black", position = "stack", stat = "identity", mapping = aes(pattern = class), linewidth = 0.15, pattern = "circle", pattern_density = 0.2, pattern_spacing = 0.01, pattern_angle = 120) +
  scale_pattern_fill_manual(values = c(c1= 'black', c2 = 'white'))+
  scale_pattern_color_manual(values = c(c1= 'black', c2 = 'white'))+
  scale_fill_manual(values = colors.df$color)+
  theme_minimal()

Which comes close: enter image description here

But unfortunately it does not color-code the patterns as I'm trying to specify in my command.

Any idea?

that I would like to plot using R ggplot2 as a stacked bar plot, where each bar is a


Solution

  • You have a few issues.

    Firstly, your mapping of the pattern aesthetic to class is over-ridden by setting pattern = "circle" later in the call to geom_bar_pattern. If you just want different colored circles as the pattern fill, you will need to specify a scale_pattern_manual with values = c("circle", "circle")).

    Secondly, to keep the bar segments in the correct order, you will need to use group = interaction(class, group) as part of the mapping.

    Thirdly, your scale_ calls aren't doing anything because pattern_fill and pattern_color are separate aesthetics that you haven't mapped yet.

    Finally, you have some redundancy. geom_bar(stat = "identity") was superseded by geom_col several years ago, and position = "stack" is already the default.

    Fixing all this, we have:

    library(ggplot2)
    library(ggpattern)
    
    ggplot(df, aes(type,f, fill = group)) +
      geom_col_pattern(aes(pattern = class, group = interaction(class, group),
                           pattern_fill = class, pattern_color = class), 
                       linewidth = 0.15, pattern_density = 0.2,
                       pattern_spacing = 0.01, pattern_angle = 120) +
      scale_pattern_fill_manual(values = c(c1 = 'black', c2 = 'white')) +
      scale_pattern_color_manual(values = c(c1 = 'black', c2 = 'white')) +
      scale_pattern_manual(values = c("circle", "circle")) +
      scale_fill_manual(values = colors.df$color) +
      theme_minimal(16)
    

    enter image description here