ggplot2 facet_grid with distinct x-axis labels using facet_grid

北城余情 提交于 2020-01-14 03:17:45

问题


I've been stuck on this issue for a long time. Basically I need to generate stacked bar plots of bacterial taxa in a 2 dimensional facet_grid. This is not a problem - however, I do need to use 2 different x-axis labels plots.

I've looked at these threads which help, but still not satisfying:

Force x-axis labels on facet_grid ggplot: drop lables

Force x-axis labels on facet_grid ggplot: x-axis labels differ per row

Force X axis text on for all facets of a facet_grid plot

My first data frame:

structure(list(variable = structure(c(1L, 1L, 1L, 15L, 15L, 15L, 
8L, 8L, 8L, 14L, 14L, 14L, 11L, 11L, 11L, 6L, 6L, 6L, 9L, 9L, 
9L, 2L, 2L, 2L, 4L, 4L, 4L, 13L, 13L, 13L, 12L, 12L, 12L, 10L, 
10L, 10L, 3L, 3L, 3L, 7L, 7L, 7L, 5L, 5L, 5L), .Label = c("Control-5C10-7F", 
"Control-5C20-7M", "Treatment-5T16-7M", "Treatment-5T10-7F", 
"Treatment-5T20-7F", "Control-5C18-7F", "Treatment-5T17-7F", 
"Control-5C11-7F", "Control-5C19-7M", "Treatment-5T16-7F", "Control-5C17-7F", 
"Treatment-5T11-7M", "Treatment-5T10-7M", "Control-5C11-7M", 
"Control-5C10-7M"), class = "factor"), value = c(0.331838128419, 
0.352404886374, 0.0718854601356, 0.354207630618, 0.294475795902, 
0.0531792027053, 0.29236332445, 0.468273675353, 0.0607016856192, 
0.293872306838, 0.362196681338, 0.066892937885, 0.365593390631, 
0.307405564259, 0.0440421535284, 0.355757725414, 0.344565656834, 
0.0385728714381, 0.321804993859, 0.357477936005, 0.0189435852408, 
0.29485205349, 0.323279812948, 0.0613479971185, 0.330899082108, 
0.0950818222943, 0.00477515444166, 0.382399029908, 0.118943005246, 
0.00476898392234, 0.369726433283, 0.163932867784, 0.00531688661114, 
0.309218704951, 0.146836936202, 0.196198995646, 0.395112160831, 
0.185072972204, 0.00267743643869, 0.306483893184, 0.330640754636, 
0.0715509081212, 0.301275805191, 0.388917814857, 0.0356065705157
), Type = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 
2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 
2L, 2L, 2L), .Label = c("Control", "Treatment"), class = "factor"), 
    Time.Sex = structure(c(2L, 2L, 2L, 1L, 1L, 1L, 2L, 2L, 2L, 
    1L, 1L, 1L, 2L, 2L, 2L, 2L, 2L, 2L, 1L, 1L, 1L, 1L, 1L, 1L, 
    2L, 2L, 2L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 1L, 1L, 1L, 
    2L, 2L, 2L, 2L, 2L, 2L), .Label = c("7d.M", "7d.F"), class = "factor"), 
    IndividualID = c("5C10", "5C10", "5C10", "5C10", "5C10", 
    "5C10", "5C11", "5C11", "5C11", "5C11", "5C11", "5C11", "5C17", 
    "5C17", "5C17", "5C18", "5C18", "5C18", "5C19", "5C19", "5C19", 
    "5C20", "5C20", "5C20", "5T10", "5T10", "5T10", "5T10", "5T10", 
    "5T10", "5T11", "5T11", "5T11", "5T16", "5T16", "5T16", "5T16", 
    "5T16", "5T16", "5T17", "5T17", "5T17", "5T20", "5T20", "5T20"
    ), Sex = c("F", "F", "F", "M", "M", "M", "F", "F", "F", "M", 
    "M", "M", "F", "F", "F", "F", "F", "F", "M", "M", "M", "M", 
    "M", "M", "F", "F", "F", "M", "M", "M", "M", "M", "M", "F", 
    "F", "F", "M", "M", "M", "F", "F", "F", "F", "F", "F"), Rep = c(1, 
    1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 3, 3, 
    3, 4, 4, 4, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 
    3, 3, 3, 4, 4, 4), IndividualID.Sex = c("5C10.F", "5C10.F", 
    "5C10.F", "5C10.M", "5C10.M", "5C10.M", "5C11.F", "5C11.F", 
    "5C11.F", "5C11.M", "5C11.M", "5C11.M", "5C17.F", "5C17.F", 
    "5C17.F", "5C18.F", "5C18.F", "5C18.F", "5C19.M", "5C19.M", 
    "5C19.M", "5C20.M", "5C20.M", "5C20.M", "5T10.F", "5T10.F", 
    "5T10.F", "5T10.M", "5T10.M", "5T10.M", "5T11.M", "5T11.M", 
    "5T11.M", "5T16.F", "5T16.F", "5T16.F", "5T16.M", "5T16.M", 
    "5T16.M", "5T17.F", "5T17.F", "5T17.F", "5T20.F", "5T20.F", 
    "5T20.F"), Genus = c("o__Bacteroidales;g__Parabacteroides", 
    "o__Lactobacillales;g__Lactobacillus", "o__Clostridiales;g__Lachnospiraceae NK4A136 group", 
    "o__Bacteroidales;g__Parabacteroides", "o__Lactobacillales;g__Lactobacillus", 
    "o__Clostridiales;g__Lachnospiraceae NK4A136 group", "o__Bacteroidales;g__Parabacteroides", 
    "o__Lactobacillales;g__Lactobacillus", "o__Clostridiales;g__Lachnospiraceae NK4A136 group", 
    "o__Bacteroidales;g__Parabacteroides", "o__Lactobacillales;g__Lactobacillus", 
    "o__Clostridiales;g__Lachnospiraceae NK4A136 group", "o__Bacteroidales;g__Parabacteroides", 
    "o__Lactobacillales;g__Lactobacillus", "o__Clostridiales;g__Lachnospiraceae NK4A136 group", 
    "o__Bacteroidales;g__Parabacteroides", "o__Lactobacillales;g__Lactobacillus", 
    "o__Clostridiales;g__Lachnospiraceae NK4A136 group", "o__Bacteroidales;g__Parabacteroides", 
    "o__Lactobacillales;g__Lactobacillus", "o__Clostridiales;g__Lachnospiraceae NK4A136 group", 
    "o__Bacteroidales;g__Parabacteroides", "o__Lactobacillales;g__Lactobacillus", 
    "o__Clostridiales;g__Lachnospiraceae NK4A136 group", "o__Bacteroidales;g__Parabacteroides", 
    "o__Lactobacillales;g__Lactobacillus", "o__Clostridiales;g__Lachnospiraceae NK4A136 group", 
    "o__Bacteroidales;g__Parabacteroides", "o__Lactobacillales;g__Lactobacillus", 
    "o__Clostridiales;g__Lachnospiraceae NK4A136 group", "o__Bacteroidales;g__Parabacteroides", 
    "o__Lactobacillales;g__Lactobacillus", "o__Clostridiales;g__Lachnospiraceae NK4A136 group", 
    "o__Bacteroidales;g__Parabacteroides", "o__Lactobacillales;g__Lactobacillus", 
    "o__Clostridiales;g__Lachnospiraceae NK4A136 group", "o__Bacteroidales;g__Parabacteroides", 
    "o__Lactobacillales;g__Lactobacillus", "o__Clostridiales;g__Lachnospiraceae NK4A136 group", 
    "o__Bacteroidales;g__Parabacteroides", "o__Lactobacillales;g__Lactobacillus", 
    "o__Clostridiales;g__Lachnospiraceae NK4A136 group", "o__Bacteroidales;g__Parabacteroides", 
    "o__Lactobacillales;g__Lactobacillus", "o__Clostridiales;g__Lachnospiraceae NK4A136 group"
    ), variable2 = c("7d.F-1", "7d.F-1", "7d.F-1", "7d.M-1", 
    "7d.M-1", "7d.M-1", "7d.F-2", "7d.F-2", "7d.F-2", "7d.M-2", 
    "7d.M-2", "7d.M-2", "7d.F-3", "7d.F-3", "7d.F-3", "7d.F-4", 
    "7d.F-4", "7d.F-4", "7d.M-3", "7d.M-3", "7d.M-3", "7d.M-4", 
    "7d.M-4", "7d.M-4", "7d.F-1", "7d.F-1", "7d.F-1", "7d.M-1", 
    "7d.M-1", "7d.M-1", "7d.M-2", "7d.M-2", "7d.M-2", "7d.F-2", 
    "7d.F-2", "7d.F-2", "7d.M-3", "7d.M-3", "7d.M-3", "7d.F-3", 
    "7d.F-3", "7d.F-3", "7d.F-4", "7d.F-4", "7d.F-4"), pos = c(0.1, 
    0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 
    0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.2, 
    0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 
    0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2)), .Names = c("variable", 
"value", "Type", "Time.Sex", "IndividualID", "Sex", "Rep", "IndividualID.Sex", 
"Genus", "variable2", "pos"), row.names = c(NA, -45L), class = "data.frame")

The second data frame used in the internal function of ggplot.

structure(list(variable2 = c("7d.F-1", "7d.M-1", "7d.F-2", "7d.M-2", 
"7d.F-3", "7d.F-4", "7d.M-3", "7d.M-4", "7d.F-1", "7d.M-1", "7d.M-2", 
"7d.F-2", "7d.M-3", "7d.F-3", "7d.F-4"), IndividualID = c("5C10", 
"5C10", "5C11", "5C11", "5C17", "5C18", "5C19", "5C20", "5T10", 
"5T10", "5T11", "5T16", "5T16", "5T17", "5T20"), Type = structure(c(1L, 
1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 2L, 2L, 2L), .Label = c("Control", 
"Treatment"), class = "factor")), .Names = c("variable2", "IndividualID", 
"Type"), row.names = c(1L, 4L, 7L, 10L, 13L, 16L, 19L, 22L, 25L, 
28L, 31L, 34L, 37L, 40L, 43L), class = "data.frame")

My code:

index_x <<-  0
index_k <<-  0
p <- ggplot(data=df, aes(x=variable2, y=value, fill=Genus)) +
   facet_grid("Type ~ Time.Sex", scales="free_x", space="free_x") +
   geom_bar(stat="identity", size=0.0) +
   geom_bar( size=0.0, stat="identity", show.legend=FALSE) +
##I tried with some level of success to include the labels I want inside the stacked bars themselves, but 
   ## would ideally like them to be on the x-axis.
   geom_text(aes(y=pos, label=IndividualID), vjust=0, angle=90, size=3) +
   xlab("Category") +
   ylab("Abundance %") +
   ggtitle(paste0("Taxa abundance")) +
   theme(
      panel.border=element_rect(fill=NA, linetype="solid", colour = "black", size=0.25),
      axis.text.x=element_text(size=9, colour="black", angle=as.numeric(90)),
      axis.text.y=element_text(size=9, colour="black"),
      axis.title=element_text(family="Helvetica", size=10),
      plot.title = element_text(lineheight=1.2, face="bold", size=25),
      panel.grid.major=element_blank(),
      panel.grid.minor=element_blank(),
      panel.background=element_blank(),
      legend.key.size = unit(0.35, "cm"),
      legend.text = element_text(size=12, face="bold"),
      legend.title = element_text(size=12, face="bold"),
      legend.spacing = unit(1, "cm"),
      legend.position="right",
      strip.text.x = element_text(angle=90, vjust=0, size=7, face="bold"),
      strip.text.y = element_text(hjust=0, angle=0, size=7, face="bold"),
      strip.background =  element_blank(),
      panel.spacing.y = unit(0.3, "lines")
   ) +  scale_fill_manual(values=vColors) +
   ## I wrote an internal function to force the x labels
   scale_x_discrete(name="IndividualID", labels = function(x){

      final_labels = c()

      if(index_x %% length(curr_order_x) == 0){
         index_k <<- index_k + 1
      }
      df_labels2 = df_labels_orig[df_labels_orig[[ facets[1] ]] == rev(curr_order_y)[index_k], ]

      for(i in 1:length(x)){
         final_labels = c(final_labels, df_labels2[df_labels2$variable2 == x[i],]$IndividualID)
      }
      index_x <<- index_x + 1

      print(final_labels)
      return(final_labels)
   }  
   )
print(p)

For which I get the following: But what I'd like to have are the Individual IDs that are in the stacked bars themselves just below on the x-axis. So here is what I did, thinking I could display the forced x-axis labels from the internal function above using gTable.

# Then following the references I found on SO, I tried the following:
index_x <<- 0 
index_k <<- 0

g <- ggplotGrob(p)

panels <- grep("panel", g$layout$name)
top <- unique(g$layout$t[panels])

top.row <- gtable:::rbind_gtable(
   g[seq.int(min(top)), ],
   g[max(top)+1,], "first"
)
bottom.row <- g[(max(top)-1):nrow(g), ]
all <- gtable:::rbind_gtable(top.row, bottom.row, "first")
grid.newpage()
grid.draw(all)

For which I obtain: The x-axis is the same on the two rows and I'd like them to correspond to what they actually represent. It seems to work well for the bottom panels, but the upper panels x-axis labels contain the same labels as the ones on the lower panels. I've also lost the legend.

Edit: Here is what I'd like to have for final result:


回答1:


Rather than adjusting to the settings of facet_grid, consider building plots individually according to the needed groupings. Specifically, consider base R's by (that slices a dataframe by factor(s)) to build a list of plots according to your levels, Type and Time.Sex.

However, adjustments need to be made to fit your requirements:

  1. Place Control plots above Treatment plots;
  2. Adjust axes to avoid redundancy (tailored to actual number of plots, here being 4):
    • Remove the y-axis title/text/tick marks on 2nd and 4th;
    • Remove the x-axis title on 1st and 2nd plots;
  3. Avoid multiple legends by using @baptist's share a legend method.

Share a Legend (adjusted to read in a list of plots as first argument and adds a title at top)

# CREDIT: @Baptist: https://github.com/tidyverse/ggplot2/wiki/Share-a-legend-between-two-ggplot2-graphs
grid_arrange_shared_legend <- function(plots, ncol = length(list(...)), nrow = 1, position = c("bottom", "right")) {

  position <- match.arg(position)
  g <- ggplotGrob(plots[[1]] + theme(legend.position = position))$grobs
  legend <- g[[which(sapply(g, function(x) x$name) == "guide-box")]]
  lheight <- sum(legend$height)
  lwidth <- sum(legend$width)
  gl <- lapply(plots, function(x) x + theme(legend.position="none"))
  gl <- c(gl, ncol = ncol, nrow = nrow)

  title <- textGrob("Taxa Abundance",gp=gpar(fontsize=20))

  combined <- switch(position,
                     "bottom" = arrangeGrob(do.call(arrangeGrob, gl),
                                            legend,
                                            ncol = 1,
                                            top = title,
                                            heights = unit.c(unit(0.95, "npc") - lheight, lheight)),
                     "right" = arrangeGrob(do.call(arrangeGrob, gl),
                                           legend,
                                           ncol = 2,
                                           widths = unit.c(unit(1, "npc") - lwidth, lwidth)))

  grid.newpage()
  grid.draw(combined)

  # return gtable invisibly
  invisible(combined)

}

R (using by() plots)

vColors <- c("red", "green", "blue")

by_plots <- by(df, df[,c("Type", "Time.Sex")], FUN=function(sub)       
  ggplot(sub, aes(x=IndividualID, y=value, fill=factor(Genus))) +
    geom_bar(stat="identity", size=0.0) + 
    labs(title=paste(sub$Type[[1]], "-", sub$Time.Sex[[1]]), x="Category", y="Abundance %") + 
    guides(fill=guide_legend(title="Genus", nrow=3)) + ylim(0, 0.9) +
    scale_fill_manual(values=vColors) +
    theme(plot.title = element_text(hjust = 0.5))
)

# RE-ORDER FOR CONTROL PLOTS ABOVE TREATMENT PLOTS
by_plots <- by_plots[c(1,3,2,4)]

# CONDITIONALLY REMOVE Y-AXIS AND X-AXIS TITLE    
by_plots <- lapply(seq_along(by_plots), function(i) {
  if ((i %% 2) == 0)
    by_plots[[i]] <- by_plots[[i]] + theme(axis.title.y = element_blank(),
                                           axis.text.y = element_blank(),
                                           axis.ticks.y = element_blank())

  if (i < 3)
    by_plots[[i]] <- by_plots[[i]] + theme(axis.title.x = element_blank())      

  return(by_plots[[i]])
})

grid_arrange_shared_legend(by_plots, ncol=2, nrow=2)

Output



来源:https://stackoverflow.com/questions/50513257/ggplot2-facet-grid-with-distinct-x-axis-labels-using-facet-grid

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!