【问题标题】:How to arrange plots with shared axes?如何用共享轴排列图?
【发布时间】:2014-09-17 14:42:57
【问题描述】:

我正在尝试创建具有共享轴和边缘直方图的三个散点图的排列。这看起来应该很简单,但它让我很适合。我尝试过使用 gridExtra 和 gtable 的方法,这两种方法都得到了我想要的总体布局,但对齐和绘图大小都关闭了。

还有许多其他帖子与这个问题相关,我已经尝试了其中许多人的答案,尤其是来自@baptiste herehere 的答案。后者控制宽度的方法可能是对齐的关键,但我对它的理解还不够好,无法适应我的问题。

下面是一个最小的工作示例,前面是它的结果。结果有不少问题:

  • 右下图比其他两个大。这一直是所有方法的问题,包括 grid.arrange(),我用它放置了一个空白矩形 grob 来平衡散点图。
  • maringal 直方图的大小与我对代码的预期不符,即它们的窄尺寸约为散点图宽度大小的 1/4。
  • 地块的间距太宽。
  • 没有一个边缘直方图与散点图正确对齐。
  • 右侧 (c) 的边缘直方图非常窄,以至于它根本不会显示在 png 中,但它确实会显示在 RStudio 绘图查看器中(尽管仍然太窄),但仅在“缩放”时”。

即使坐标轴标签的宽度在图之间发生变化,答案也会正确对齐图的坐标轴,这样可以更适应未来的问题。

library(ggplot2)
library(grid)
library(gtable)
data <- data.frame(a = rnorm(100, 30, 3), b = rnorm(100, 40, 5), c=rnorm(100, 50, 3))
b_a.scatter <- ggplot(data, aes(x=a, y=b)) + geom_point() + coord_equal(ratio=1, xlim=c(0,100), ylim=c(0,100)) +
  theme(
    axis.text.x  = element_blank(),
    axis.title.x = element_blank(),
    axis.ticks.x = element_blank(),
    plot.margin  = unit(c(1,0,-0.5,1), "cm")
  )

c_a.scatter <- ggplot(data, aes(x=a, y=c)) + geom_point() + coord_equal(ratio=1, xlim=c(0,100), ylim=c(0,100)) +
  theme(plot.margin = unit(c(-0.5,0,0.5,1), "cm"))

c_b.scatter <- ggplot(data, aes(x=b, y=c)) + geom_point() + coord_equal(ratio=1, xlim=c(0,100), ylim=c(0,100)) +
  theme(
    axis.text.y  = element_blank(),
    axis.title.y = element_blank(),
    axis.ticks.y = element_blank(),
    plot.margin  = unit(c(-0.5,0,0.5,0), "cm")
  )

a.hist <- ggplot(data, aes(x=a)) + geom_histogram() + coord_equal(xlim=c(0,100), ratio=1/4) +
  theme(
    axis.text.x  = element_blank(),
    axis.title.x = element_blank(),
    axis.ticks.x = element_blank(),
    axis.text.y  = element_blank(),
    axis.title.y = element_blank(),
    axis.ticks.y = element_blank(),
    plot.margin = unit(c(0,0,1,1), "cm")
  )

b.hist <- ggplot(data, aes(x=b)) + geom_histogram() + coord_equal(xlim=c(0,100), ratio=1/4) +
  theme(
    axis.text.x  = element_blank(),
    axis.title.x = element_blank(),
    axis.ticks.x = element_blank(),
    axis.text.y  = element_blank(),
    axis.title.y = element_blank(),
    axis.ticks.y = element_blank(),
    plot.margin = unit(c(0,0,1,0), "cm")
  )

c.hist <- ggplot(data, aes(x=c)) + geom_histogram() + coord_flip(xlim=c(0,100)) +
  theme(
    axis.text.x  = element_blank(),
    axis.title.x = element_blank(),
    axis.ticks.x = element_blank(),
    plot.margin = unit(c(0,1,0,0), "cm")
  )

blankPanel <- grid.rect(gp=gpar(col="white"))

gt <- gtable(widths  = unit(rep(1,9), "null"),
             heights = unit(rep(1,9), "null"),
             respect=T)
gl <- list(ggplotGrob(b_a.scatter),
             ggplotGrob(c_a.scatter), ggplotGrob(c_b.scatter), ggplotGrob(c.hist),
             ggplotGrob(a.hist), ggplotGrob(b.hist))

gt <- gtable_add_grob(gt, gl,
                l=c(1,1,5,9,1,5),
                r=c(4,4,8,9,4,8),
                t=c(1,5,5,5,9,9),
                b=c(4,8,8,8,9,9))

grid.newpage()
png('multiplot.png')
grid.draw(gt)
dev.off()

【问题讨论】:

    标签: r ggplot2 gtable r-grid


    【解决方案1】:

    这是一种方法:使用 rbind 逐列组合图形,然后对三列进行 cbind。为空单元格提供了虚拟 gtable,它们仅包含布局信息。

    library(ggplot2)
    library(gtable)
    d <- data.frame(a = rnorm(100, 30, 3), 
                    b = rnorm(100, 40, 5), 
                    c=rnorm(100, 50, 3))
    
    theme_set(theme_bw() + 
                theme(plot.background=element_rect(colour="red",size = 2)))
    ## define simpler plots
    a <- ggplot(d, aes(x=a, y=b)) + geom_point() + xlim(0,100)+ ylim(0,90)
    b <- ggplot(d, aes(x=a, y=c)) + geom_point() + xlim(0,100) + ylim(0,90)
    c <- ggplot(d, aes(x=b, y=c)) + geom_point() + xlim(0,100) + ylim(0,90)
    ah <- ggplot(d, aes(x=a)) + geom_histogram() + 
      xlim(0,100)+ ylim(0,2000000) 
    bh <- ggplot(d, aes(x=b)) + geom_histogram() + 
      xlim(0,100) + ylim(0,2000000) 
    ch <- ggplot(d, aes(x=c)) + geom_histogram() + 
      coord_flip(xlim=c(0,200000))
    
    pl <- lapply(list(a,b,c,ah,bh,ch), ggplotGrob)
    
    ## function to create a dummy table (no grobs, zero size) of the right dim for (r/c)bind
    dummy_gtable <- function(g){
      gtable(widths=unit(rep(0,ncol(g)), 'null'), heights=unit(rep(0, nrow(g)), 'null'))
    }
    
    left <- rbind(pl[[1]],pl[[2]],pl[[4]])
    middle <- rbind(dummy_gtable(pl[[1]]),pl[[3]],pl[[5]])
    right <- rbind(dummy_gtable(pl[[1]]),pl[[6]], dummy_gtable(pl[[5]]))
    grid.newpage()
    grid.draw(cbind(left, middle, right))
    

    请注意,我使用my experimental fork of gtable 中的cbindrbind,因为发布的版本不使用unit.pmax 作为宽度和高度的单位比较。可以从 another question 借用自定义函数以继续使用稳定的 gtable 版本。

    【讨论】:

    • dummy_gtable() 函数似乎存在问题,因为left &lt;- rbind_gtable_max(...) 工作正常但middle &lt;- rbind_table_max(dummy_gtable(...)) 返回。 Error: is.unit(widths) is not TRUE。请注意,我将您在上面的解决方案中定义的 rbind_gtable_max 和 cbind_gtable_max 函数替换为 here 的 rbind 和 cbind 函数。
    • 这可能是因为 this pull request 我在我的 fork 中合并了,但仍然在 gtable 官方版本中等待。试试新代码。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-24
    • 2021-11-22
    • 2020-07-07
    • 1970-01-01
    • 1970-01-01
    • 2019-05-31
    相关资源
    最近更新 更多