首页 文章

在facet_wrap图中添加“浮动”轴标签

提问于
浏览
42

我和this用户有同样的问题 - 我有一个'jagged'刻面图,其中底行的面板比其他行少,我想在每列的底部有x轴刻度 .

针对该问题的建议解决方案是设置 scales="free_x" . (在ggplot 0.9.2.1中;我认为我的行为在我的情况下是一个糟糕的解决方案:我的实际轴标签会相当长,所以将它们放在每一行下会占用太多空间 . 结果是这样的:

x <- gl(3, 1, 15, labels=paste("this is a very long axis label ", letters[1:5]))
 y <- rnorm(length(x))
 l <- gl(5, 3, 15)
 d <- data.frame(x=x, y=y, l=l)
 ggplot(d, aes(x=x, y=y)) + geom_point() + facet_wrap(~l, scales="free_x") + 
   theme(axis.text.x=element_text(angle=90, hjust=1))

enter image description here

在评论here中,Andrie建议可以在 grid 手动完成,但我不知道如何开始 .

1 回答

  • 61

    如果我没记错的话,对于如何将所有标签添加到最后一列下的同一行以及如何将这些最后标签提升到下一行存在疑问 . 所以这是两种情况的功能:

    Edit: 因为这就像 print.ggplot 的替代品(见 getAnywhere(print.ggplot) )我已经添加了一些行来保留功能 .

    Edit 2: 我已经改进了一点:不再需要指定 nrowncol ,所有面板的图也可以打印 .

    library(grid)
    # pos - where to add new labels
    # newpage, vp - see ?print.ggplot
    facetAdjust <- function(x, pos = c("up", "down"), 
                            newpage = is.null(vp), vp = NULL)
    {
      # part of print.ggplot
      ggplot2:::set_last_plot(x)
      if(newpage)
        grid.newpage()
      pos <- match.arg(pos)
      p <- ggplot_build(x)
      gtable <- ggplot_gtable(p)
      # finding dimensions
      dims <- apply(p$panel$layout[2:3], 2, max)
      nrow <- dims[1]
      ncol <- dims[2]
      # number of panels in the plot
      panels <- sum(grepl("panel", names(gtable$grobs)))
      space <- ncol * nrow
      # missing panels
      n <- space - panels
      # checking whether modifications are needed
      if(panels != space){
        # indices of panels to fix
        idx <- (space - ncol - n + 1):(space - ncol)
        # copying x-axis of the last existing panel to the chosen panels 
        # in the row above
        gtable$grobs[paste0("axis_b",idx)] <- list(gtable$grobs[[paste0("axis_b",panels)]])
        if(pos == "down"){
          # if pos == down then shifting labels down to the same level as 
          # the x-axis of last panel
          rows <- grep(paste0("axis_b\\-[", idx[1], "-", idx[n], "]"), 
                       gtable$layout$name)
          lastAxis <- grep(paste0("axis_b\\-", panels), gtable$layout$name)
          gtable$layout[rows, c("t","b")] <- gtable$layout[lastAxis, c("t")]
        }
      }
      # again part of print.ggplot, plotting adjusted version
      if(is.null(vp)){
        grid.draw(gtable)
      }
      else{
        if (is.character(vp)) 
          seekViewport(vp)
        else pushViewport(vp)
        grid.draw(gtable)
        upViewport()
      }
      invisible(p)
    }
    

    这是它的外观

    d <- ggplot(diamonds, aes(carat, price, fill = ..density..)) +
      xlim(0, 2) + stat_binhex(na.rm = TRUE) + theme(aspect.ratio = 1) + 
      facet_wrap(~ color)
    facetAdjust(d)
    

    enter image description here

    facetAdjust(d, "down")
    

    enter image description here

    Edit 3:

    这是一种替代解决方案,上面的解决方案也很好 .

    当想要与 facetAdjust 一起使用 ggsave 时,存在一些问题 . 需要 ggplot 类的图,因为 ggsave 的源代码中有两个部分: print(plot)default_name(plot) ,以防一个人手动提供文件名(根据 ?ggsave ,似乎它不应该工作) . 因此,给定一个文件名,有一个解决方法(在某些情况下可能有副作用):

    首先,让我们考虑实现浮动轴主效应的单独函数 . 通常,它会返回 gtable 对象,但是我们使用 class(gtable) <- c("facetAdjust", "gtable", "ggplot") . 通过这种方式,可以根据需要使用 ggsaveprint(plot) (参见下面的 print.facetAdjust

    facetAdjust <- function(x, pos = c("up", "down"))
    {
      pos <- match.arg(pos)
      p <- ggplot_build(x)
      gtable <- ggplot_gtable(p); dev.off()
      dims <- apply(p$panel$layout[2:3], 2, max)
      nrow <- dims[1]
      ncol <- dims[2]
      panels <- sum(grepl("panel", names(gtable$grobs)))
      space <- ncol * nrow
      n <- space - panels
      if(panels != space){
        idx <- (space - ncol - n + 1):(space - ncol)
        gtable$grobs[paste0("axis_b",idx)] <- list(gtable$grobs[[paste0("axis_b",panels)]])
        if(pos == "down"){
          rows <- grep(paste0("axis_b\\-[", idx[1], "-", idx[n], "]"), 
                       gtable$layout$name)
          lastAxis <- grep(paste0("axis_b\\-", panels), gtable$layout$name)
          gtable$layout[rows, c("t","b")] <- gtable$layout[lastAxis, c("t")]
        }
      }
      class(gtable) <- c("facetAdjust", "gtable", "ggplot"); gtable
    }
    

    打印功能仅与 ggplot2:::print.ggplot 中的几行不同:

    print.facetAdjust <- function(x, newpage = is.null(vp), vp = NULL) {
      if(newpage)
        grid.newpage()
      if(is.null(vp)){
        grid.draw(x)
      } else {
        if (is.character(vp)) 
          seekViewport(vp)
        else pushViewport(vp)
        grid.draw(x)
        upViewport()
      }
      invisible(x)
    }
    

    例:

    d <- ggplot(diamonds, aes(carat, price, fill = ..density..)) +
      xlim(0, 2) + stat_binhex(na.rm = TRUE) + theme(aspect.ratio = 1) + 
      facet_wrap(~ color)
    p <- facetAdjust(d) # No output
    print(p) # The same output as with the old version of facetAdjust()
    ggsave("name.pdf", p) # Works, a filename is necessary
    

相关问题