【问题标题】:Align gridArranged facetted ggplots对齐 gridArranged facetted ggplots
【发布时间】:2014-03-18 09:16:25
【问题描述】:

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

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)

这给了我这个:

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

【问题讨论】:

    标签: r ggplot2 gridextra facet-wrap


    【解决方案1】:

    这是一个解决方案,来自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)
    

    【讨论】:

    • 我刚刚让这个完全可重现。 drop=FALSE 不起作用,因为没有任何 NA ids 可以删除。如果我理解facet_grid 对,那只允许我有一个包含三列(每组一个)的图,但是我需要适合所有ids 的行数。对吗?
    • group 变量是否具有分析意义,还是只是为了将图表分成列而包含在内?
    • 不确定您所说的“分析意义”是什么意思,以及为什么会有所作为。这些是来自实验的数据,groups 是真正不同的处理方法。但出于绘图的目的,这些组仅用于将ids 分成三列
    • “分析意义”是指它实际上是您实验中的一个因素。如果各组是不同的治疗方法,听起来像“是”。基本上,您希望保留 x 和 y 方向的比例。设置nrow 而不是ncol 并将widths 参数添加到grid.arrange。在上面编辑了我的解决方案。
    • 这会起作用,但会为第三组产生四个子列。我宁愿每个子列有三个子列,并通过在底部添加空闲空间来对齐。也许我应该在我原来的问题中更准确。
    【解决方案2】:

    这有点乱,但你可以按摩 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)
    

    【讨论】:

    • 这是朝着正确的方向发展,但第三列中的刻面不等间距(可能是因为其他两列的 x 轴占用了该空间)。跨度>
    • 使用这种方法确实需要特别注意轴,这需要我花更多的时间才能做到正确。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-06-07
    • 1970-01-01
    • 2021-10-17
    • 1970-01-01
    • 1970-01-01
    • 2021-04-14
    • 1970-01-01
    相关资源
    最近更新 更多