对齐网格排列多面ggplots

时间:2014-02-18 14:29:39

标签: r ggplot2 gridextra facet-wrap

我已经创建了一个分面图,分别针对我的数据中的三个不同组,如下所示:

df <- data.frame(x=rep(seq(0.05,1,by=0.05),times=40),
                 y=sample(c('A','B'),20*40,replace=TRUE),
                 id=rep(1:40,each=20),
                 group=c(rep(1,20*12),rep(2,20*12),rep(3,20*16)))

g1 <- ggplot(df[df$group==1,],aes(x,y,group=id))
g1 <- g1 + geom_line()
g1 <- g1 + facet_wrap(~id,ncol=3)

g2 <- ggplot(df[df$group==2,],aes(x,y,group=id))
g2 <- g2 + geom_line()
g2 <- g2 + facet_wrap(~id,ncol=3)

g3 <- ggplot(df[df$group==3,],aes(x,y,group=id))
g3 <- g3 + geom_line()
g3 <- g3 + facet_wrap(~id,ncol=3)

grid.arrange(g1,g2,g3,nrow=1)

给了我这个:

enter image description here

如您所见,三组之间的构面数量不同,这意味着三列中的构面具有不同的高度。有没有办法以非脆弱的方式协调这个高度(即,我不必手动确定第2列和第3列的高度,这使得我的方面看起来像是大致相同的高度)?

2 个答案:

答案 0 :(得分:1)

enter image description here这是一个解决方案,其中包含this question的一些指导。

library(ggplot2)
library(gridExtra)


ncol = 3 
df <- data.frame(x=rep(seq(0.05,1,by=0.05),times=40),
                 y=factor(sample(c('A','B'),20*40,replace=TRUE), levels = c("A", "B")),
                 id=rep(1:40,each=20),
                 group=c(rep(1,20*12),rep(2,20*12),rep(3,20*16)))

max_cases <- max(table(unique(df[,c("id", "group")])$group))

# create phantom plots for everything in the containing rectangle to standardize labels
rect_dim <- ceiling(max_cases / ncol) * ncol

plots <- lapply(X=unique(df$group), FUN= function(i){

  df_case <- subset(df, subset= group == i)
  tot_case <- nrow(unique(df_case[,c("id", "group")]))
  # create fill levels to pad the plots
  fill_levels <- unlist(lapply(X=1:(rect_dim - tot_case), function(y){paste0(rep(x=" ", times=y), collapse="")}))
  df_case$id.label <- ordered(df_case$id, levels = c(unique(df_case$id), fill_levels))

  g_case <- ggplot(df_case,aes(x,y,group=id.label)) + 
    geom_line() +
    facet_wrap(~id.label, ncol = ncol, drop=FALSE)

  # whiteout the inner y axis elements to clean it up a bit
  if(i != 1){
    g_case <- g_case + theme(axis.text.y = element_text(color = "white"), 
                             axis.title.y = element_text(color = "white"),
                             axis.ticks.y = element_line(color = "white"))
  }

  g_case <- ggplotGrob(g_case)
  rm_me <- (tot_case:rect_dim)[-1]
  # remove empty panels and layout
  g_case$grobs[names(g_case$grobs) %in% c(paste0("panel", rm_me), paste0("strip_t.", rm_me))] <- NULL
  g_case$layout <- g_case$layout[!(g_case$layout$name %in% c(paste0("panel-", rm_me), paste0("strip_t-", rm_me))),]
  g_case
})

plots$nrow = 1
do.call("grid.arrange", plots)

答案 1 :(得分:1)

它有点乱,但是您可以按下gtables以获得相同数量的行,并对齐它们。进一步细化将找到与绘图面板对应的行,而不是假设所有绘图具有相同的面板轴行序列 - 等等。

library(gtable)

cbind_top = function(...){
  pl <- list(...)
  ## test that only passing plots
  stopifnot(do.call(all, lapply(pl, inherits, "gg")))
  gl <- lapply(pl, ggplotGrob)
  nrows <- sapply(gl, function(x) length(x$heights))
  tallest <- max(nrows)
  add_dummy <- function(x, n){
    if(n == 0) return(x)
    gtable_add_rows(x, rep(unit(0, "mm"), n), nrow(x)-2)
  }
  gl <- mapply(add_dummy, x=gl, n=tallest - nrows)

  compare_unit <- function(u1,u2){
    n <- length(u1)
    stopifnot(length(u2) == n)
    null1 <- sapply(u1, attr, "unit")
    null2 <- sapply(u2, attr, "unit")
    null12 <- null1 == "null" | null2 == "null"
    both <- grid::unit.pmax(u1, u2)
    both[null12] <- rep(list(unit(1,"null")), sum(null12))
    both
  }

  bind2 <- function(x,y){
    y$layout$l <- y$layout$l + ncol(x)
    y$layout$r <- y$layout$r + ncol(x)
    x$layout <- rbind(x$layout, y$layout)
    x$widths <- gtable:::insert.unit(x$widths, y$widths)
    x$colnames <- c(x$colnames, y$colnames)
    x$heights <- compare_unit(x$heights, y$heights)
    x$grobs <- append(x$grobs, y$grobs)
    x
  }
  combined <- Reduce(bind2, gl[-1], gl[[1]])

  grid::grid.newpage()
  grid::grid.draw(combined)
}

cbind_top(g1,g2,g3)