Search code examples
rggplot2facet-wrap

ggplot 2 use facet wrap with multiple stacked barplots of frequency counts


I have a number of binary variables where I want to express the frequency of behaviours occurring (1 = present, 0 = absent) according to condition. I can successfully plot this for individual variables using the syntax below:

require(tidyverse)
require(ggplot2)
require(ggsignif)
require(ggpubr)


condition <- c("a", "a", "a", "b", "b", "b", "c", "c", "c", "c")
binary_1 <- c(0,0,0,0,0,1,1,1,1,1)
binary_2 <- c(1,1,1,1,1,1,0,0,0,0)
binary_3 <- c(0,1,1,1,1,1,1,1,0,0)
binary_4 <- c(1,1,1,0,0,0,0,0,0,0)


df <- data.frame(condition, binary_1, binary_2, binary_3, binary_4)
df

gg_df <- df %>%
  mutate(binary_1 = as.factor(binary_1), binary_2 = as.factor(binary_2), binary_3 = as.factor(binary_3), binary_4 = as.factor(binary_4))

gg_melt <- melt(gg_df)

# example for one of the variables (binary_1), I just swap the variable out for each graph
gg_1 <- ggplot(gg_melt, aes(x=condition, fill = binary_1)) +
  geom_bar(stat="count") +
  scale_fill_manual(values = c("#FDAE61", "#9E0142"), name = "Behaviour Observed", labels = c("0" = "Absent", "1" = "Present")) +
  scale_x_discrete(labels = c(a = "Condition A", b = "Condition B", c = "Condition C")) + 
  xlab("Condition") + 
  ylab("Number of Participants") +
  theme(aspect.ratio = 1)

However, since all of the variables have the same x-axis (condition) and y-axis (frequency count) I was hoping to use facet-wrap to express all the variables simultaneously on the same graph. However, I haven't seemed to be able to get it to work. I read through the following threads:

How to pass a count of observations to the facet label?

R ggplot2 using ..count.. when using facet_grid

percentage on y lab in a faceted ggplot barchart?

But I can't work out how to split by the variables, and not the count data.

# Attempt 1
gg_df %>% 
  group_by(condition) %>%
  mutate(beh_count = n()) %>%
  ungroup() %>%
  mutate(beh_updated = paste0(condition, "; n=", beh_count)) %>%
  ggplot(aes(x = condition)) + geom_bar()+
  facet_wrap(~beh_updated)

# Attempt 2
gg_df %>% 
  ggplot(aes(x = condition)) + geom_bar()+
  facet_wrap(~binary_1 + binary_2 + binary_3 + binary_4)

# Attempt 3
ggplot(data = gg_df) + 
  geom_bar(aes(condition)) + 
  facet_wrap(~binary_1 + binary_2 + binary_3 + binary_4)

How can I create a data frame with both the count data and the variables to be able to use facet wrap correctly?


Solution

  • This could be achieved by reshaping your data such that your four binary variables become categories of one variable. To this end I make use of tidyr::pivot_longer instead of reshape2::melt. After reshaping you can facet_wrap by the new variable:

    library(ggplot2)
    library(tidyr)
    library(dplyr)
    gg_df <- df %>%
       mutate(across(starts_with("binary"), as.factor))
    
    gg_melt <- tidyr::pivot_longer(gg_df, -condition, names_to = "binary")
    
    ggplot(gg_melt, aes(x=condition, fill = value)) +
      geom_bar(stat="count") +
      scale_fill_manual(values = c("#FDAE61", "#9E0142"), name = "Behaviour Observed", labels = c("0" = "Absent", "1" = "Present")) +
      scale_x_discrete(labels = c(a = "Condition A", b = "Condition B", c = "Condition C")) + 
      xlab("Condition") + 
      ylab("Number of Participants") +
      theme(aspect.ratio = 1) +
      facet_wrap(~binary)
    

    enter image description here