mellifluous
mellifluous

Reputation: 3

Nested grouping variables for stacked bar graph

I'm trying to improve the visualization of this figure by separating the x-axis into nested subcategories of samples. I'm not able to use ggplot fill for this since I've already used pivot_longer() to include 6 types of output. The solution also has to allow a free scale view using facet_wrap() to examine trends between individual protein components.

Have: Current figure

Want: Desired figure

Attempt: facet_wrap with free y-axis (pardon the x-axis labels, I've tried to conceal my actual data)

Data frame:

>head(data)
>  ShortName  Mod Growth Day    Group        Conc
>1  CTRL_D02 CTRL     CC   2 Protein1 0.013072917
>2  CTRL_D02 CTRL     CC   2 Protein2 0.000000000
>3  CTRL_D02 CTRL     CC   2 Protein3 0.004661458
>4  CTRL_D02 CTRL     CC   2 Protein4 0.000000000
>5  CTRL_D02 CTRL     CC   2 Protein5 0.000000000
>6  CTRL_D02 CTRL     CC   2 Protein6 0.025885417

>CC <- data %>% slice(1:144)
>LG <- data %>% slice(145:210)

ggplot, stacked bar graph to view broad quantity of all proteins

p0 <- ggplot(CC) + 
  geom_col(aes(x = ShortName, y = Conc, fill = Group)) + 
  theme_clean() + 
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1)) + 
  labs(y = "Concentration", x = "Sample", fill = "Composition")

ggplot, view trends of individual protein components

p0.1 <- p0 + 
  facet_wrap(. ~ Group, scales = "free_y") + 
  theme(legend.position="none")

Upvotes: 0

Views: 175

Answers (2)

Michiel Duvekot
Michiel Duvekot

Reputation: 1881

The way I've done this is to create a numerical variable in the dataframe that I can map to the x-axis, and then re-create the labels in scale_x_continuous by looking up the labels using that value. Here's a crude example using a fake dataset.

set.seed(123)

data <- data.frame(
  ShortName = sample(c( "D02", "D04", "D07", "D09", "D11", "D14"), 1250, replace = TRUE), 
  Mod = sample(c("CTRL", "P2E8", "P2G7", "poly"), 1250, replace = TRUE), 
  #Growth = sample(c("CC", "LG"), 1250, replace = TRUE), 
  #Day = sample(2:14, 1250, replace = TRUE),
  Group = sample(c("Protein1", "Protein2", "Protein3", "Protein4", "Protein5", "Protein6"), 1250, replace = TRUE),
  Conc = runif(1250, 0, 1)
) %>% 
  summarise(.by = c(-Conc), Conc = mean(Conc))

data <- data   %>%
  arrange(ShortName, Mod, Group) %>%
  mutate(
  ShortName = factor(ShortName),
  Mod = factor(Mod),
  xpos = (as.numeric(Mod))* 7 + (as.numeric(ShortName)),
  l = paste(ShortName, Mod, sep = "_")
  ) 

getlabel <- function(x){
  d <- (data[data$xpos == x,c("ShortName","Mod")][1,])
  paste(d$ShortName, d$Mod, sep = "\n")
}
getlabel <- Vectorize(getlabel)

data %>% 
  ggplot(aes(x = xpos)) + 
  geom_col(aes(y = Conc, fill = Group)) +
  scale_x_continuous(
    breaks = unique(data$xpos), 
    labels = getlabel(unique(data$xpos))
    )+
  labs(x = "sample", y = "concentration")

Upvotes: 0

Edward
Edward

Reputation: 19514

You can use the ggh4x package to do the nesting of the x-axis tick labels.

library(ggplot2); library(ggh4x)

ggplot(data, aes(x=interaction(Day,Mod), Conc, fill = Group)) + 
  geom_col() + 
  scale_x_discrete(guide="axis_nested") +  # *** ggh4x *** #
  facet_grid(~Mod, scales = 'free') +
  labs(x="Sample", y="Concentration", fill="Composition", 
       title="Stacked bar graph of convoluted timecourse") +
  #theme_clean() +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1),
        panel.grid.major.x = element_blank(), 
        panel.grid.minor.x = element_blank(),
        strip.text = element_blank(),
        axis.line.x = element_line(),
        axis.line.y = element_line(),
        legend.box.background = element_rect())

enter image description here


data <- tibble(Day=sample(c('D02','D04','D07','D11','D02','D14'), 210, TRUE),
                   Mod=sample(c('CTRL','P2E8','P2G7','poly'), 210, TRUE),
                   Growth=sample(c('CC','LG'), 210, TRUE),
                   Group=sample(paste0("Protein", 1:6), 210, TRUE, prob=c(10,1,1,1,1,1)),
                   Conc=runif(210, 0, 0.3))

Upvotes: 1

Related Questions