R 将多个复杂绘图组合为单个图形中的面板 @backlin介绍

R 将多个复杂绘图组合为单个图形中的面板 @backlin介绍,r,layout,plot,heatmap,R,Layout,Plot,Heatmap,通过使用layout或par(mfrow=…),可以将多个简单绘图组合为单个图形中的面板。但是,更复杂的绘图往往会在内部设置自己的面板布局,从而禁止将其用作面板。有没有办法创建嵌套布局并将复杂绘图封装到单个面板中 我觉得grid软件包可以实现这一点,例如,通过在单独的视口中绘制面板,但还没有弄清楚如何实现。下面是一个玩具示例来演示问题: my.plot <- function(){ a <- matrix(rnorm(100), 10, 10) plot.new()

通过使用
layout
par(mfrow=…)
,可以将多个简单绘图组合为单个图形中的面板。但是,更复杂的绘图往往会在内部设置自己的面板布局,从而禁止将其用作面板。有没有办法创建嵌套布局并将复杂绘图封装到单个面板中

我觉得
grid
软件包可以实现这一点,例如,通过在单独的视口中绘制面板,但还没有弄清楚如何实现。下面是一个玩具示例来演示问题:

my.plot <- function(){
    a <- matrix(rnorm(100), 10, 10)
    plot.new()
    par(mfrow=c(2,2))
    plot(1:10, runif(10))
    plot(hclust(dist(a)))
    barplot(apply(a, 2, mean))
    image(a)
}
layout(matrix(1:4, 2, 2))
for(i in 1:4) my.plot()
# How to avoid reseting the outer layout when calling `my.plot`?
但是,因为我想在一个绘图中比较多个热图,所以我使用
par(mfrow=c(2,2))
然后调用
heatmap.2
四次,即

row.scaled.expr <- matrix(sample(1:10000),nrow=1000,ncol=10)
arr <- array(data=row.scaled.expr, dim=c(dim(row.scaled.expr),4))
par(mfrow=c(2,2))
for (i in 1:4)
heatmap.2(arr[ , ,i], dendrogram ='row',
          Colv=FALSE, col=greenred(800), 
          key=FALSE, keysize=1.0, symkey=FALSE, density.info='none',
          trace='none', colsep=1:10,
          sepcolor='white', sepwidth=0.05,
          scale="none",cexRow=0.2,cexCol=2,
          labCol = colnames(arr[ , ,i]),                 
          hclustfun=function(c){hclust(c, method='mcquitty')},
          lmat=rbind( c(0, 3), c(2,1), c(0,4) ), lhei=c(0.25, 4, 0.25 ),                 
)

row.scaled.expr正常。我想这个问题已经有足够长的时间没有得到回答了,所以应该写下详细的答案

最困难的图形问题的答案是(正如@backlin所建议的)原始使用“网格”包。许多预构建的图形包会覆盖所有当前视口和打印设备设置,因此,如果您希望以非常特定的方式完成某些操作,则必须自己构建

我建议你读一下保罗·穆雷尔的书《R图形》,并复习一下“网格”软件包中的章节。这是一本非常有用的书,我的书桌上一直放着一本

对于你的热图,我已经写了一个快速入门,可以让你快速入门

需要了解的功能

  • grid.newpage()
    这将初始化打印设备。不带参数地使用它
  • grid.rect()
    这将绘制一个矩形。你的热图基本上只是一组巨大的彩色矩形,所以这将是你的大部分图形。它的工作原理如下:
    grid.rect(x=x\u位置,y=y\u位置,width=width\u值,height=height\u值,gpar(col=section\u颜色,fill=section\u颜色),just=c(“left”,“bottom”),default.units=“native”)
    just参数指定矩形的哪个点位于指定的(x,y)坐标上
  • grid.text()
    这将绘制文本。它的工作原理如下:
    grid.text(“标签文本”,x\u值,y\u值,gp=gpar(col=color\u值,cex=font\u大小),just=c(“右”,“中”),rot=rot\u度,默认值。units=“native”)
  • grid.lines()
    这画了一条线。它的工作原理如下:
    grid.line(c(x\u开始,x\u结束),c(y\u开始,y\u结束),gp=gpar(col=color\u值),default.units=“native”)
  • dataViewport()
    这定义了打印窗口的属性,“网格”将其称为“视口”。使用方法如下:
    pushViewport(dataViewport(扩展数据=x_数据,yData=y_数据,xscale=c(x_最小,x_最大),yscale=c(y_最小,y_最大),x=x_值,y=y_值,宽度=宽度_值,高度_值,刚好=c(“左”,“中”))
    这里有一些东西需要记住。。。请参见视口的更详细说明
  • pushViewport()
    用于初始化静脉端口。您可以围绕视口定义来实际执行视口,如下所示:
    pushViewport(dataViewport([stuff in here]))
  • popViewport()
    这将完成视口并将您在视口层次结构中上移一级。请参见视口的更详细说明
简单地说就是视口

视口是临时绘图空间,用于定义绘制“栅格”对象的位置和方式。视口中的所有内容都是相对于视口绘制的。如果视口旋转,则内部的所有内容都将旋转。视口可以嵌套,可以重叠,并且几乎无限灵活,但有一个例外:它们始终是矩形

一开始会把很多人搞糊涂的是坐标系。每个视口,包括初始的“grid.newpage()”视口,在x轴和y轴上都从0变为1。原点(0,0)是最左下角,最大值(1,1)是最右上角。这是“npc”单位制,没有指定单位集的所有东西都可能最终按照该制度绘制。这对你来说意味着两件事:

  • 指定视口大小和位置时使用“npc”系统。只要假设您的视口必须使用“npc”坐标,就可以省去很多麻烦。这意味着,如果要相邻绘制两个打印,两个视口的定义如下所示:
    • 视口(x=0,y=0,宽度=0.5,高度=1,刚度=c(“左”,“下”))
    • 视口(x=0.5,y=0,宽度=0.5,高度=1,刚度=c(“左”,“下”))
  • 如果视口具有不同的坐标系(例如用于绘制图形的视口),则需要为绘制的每个“栅格”对象指定“default.units”参数。例如,如果您试图在(2,4)处绘制一个点,您将永远看不到该点,因为它将远离屏幕。指定
    default.units=“native”
    将告诉该点使用视口自己的坐标系,并将正确绘制该点
  • 视口可以直接进行导航和写入,但除非您执行的是非常自动化的操作,否则指定视口、在其中绘制,然后“弹出”(最终确定)视口会更容易。这将返回到父视口,您可以从下一个视口开始。弹出每个视口是一种无杂乱的方法,适合大多数用途(并且更容易调试!)

    绘制图形时,“dataViewport”功能非常重要。这是一种特殊类型的视口,可以为您处理所有坐标和比例,只要您告诉它您使用的是什么数据。这是我用于任何绘图区域的。当我第一次开始使用“网格”包时,我调整了所有的值以适应“npc”坐标
    row.scaled.expr <- matrix(sample(1:10000),nrow=1000,ncol=10)
    arr <- array(data=row.scaled.expr, dim=c(dim(row.scaled.expr),4))
    par(mfrow=c(2,2))
    for (i in 1:4)
    heatmap.2(arr[ , ,i], dendrogram ='row',
              Colv=FALSE, col=greenred(800), 
              key=FALSE, keysize=1.0, symkey=FALSE, density.info='none',
              trace='none', colsep=1:10,
              sepcolor='white', sepwidth=0.05,
              scale="none",cexRow=0.2,cexCol=2,
              labCol = colnames(arr[ , ,i]),                 
              hclustfun=function(c){hclust(c, method='mcquitty')},
              lmat=rbind( c(0, 3), c(2,1), c(0,4) ), lhei=c(0.25, 4, 0.25 ),                 
    )
    
    library(gplots)
    row.scaled.expr <- matrix(sample(1:10000),nrow=1000,ncol=10)
    arr <- array(data=row.scaled.expr, dim=c(dim(row.scaled.expr),4))
    par(mfrow=c(2,2))
    for (i in 1:4) {
        ifile <- paste0(i,'_heatmap.pdf')
        pdf(ifile)
        heatmap.2(arr[ , ,i], dendrogram ='row',
                            Colv=FALSE, col=greenred(800), 
                            key=FALSE, keysize=1.0, symkey=FALSE, density.info='none',
                            trace='none', colsep=1:10,
                            sepcolor='white', sepwidth=0.05,
                            scale="none",cexRow=0.2,cexCol=2,
                            labCol = colnames(arr[ , ,i]),                 
                            hclustfun=function(c){hclust(c, method='mcquitty')},
                            lmat=rbind( c(0, 3), c(2,1), c(0,4) ), lhei=c(0.25, 4, 0.25 ),                 
        )
        dev.off()
    }
    system('montage -geometry 100% -tile 2x2 ./*_heatmap.pdf outfile.pdf')
    
    library(gridGraphics)
    library(grid)
    
    grab_grob <- function(){
      grid.echo()
      grid.grab()
    }
    
    arr <- replicate(4, matrix(sample(1:100),nrow=10,ncol=10), simplify = FALSE)
    
    library(gplots)
    gl <- lapply(1:4, function(i){
      heatmap.2(arr[[i]], dendrogram ='row',
                Colv=FALSE, col=greenred(800), 
                key=FALSE, keysize=1.0, symkey=FALSE, density.info='none',
                trace='none', colsep=1:10,
                sepcolor='white', sepwidth=0.05,
                scale="none",cexRow=0.2,cexCol=2,
                labCol = colnames(arr[[i]]),                 
                hclustfun=function(c){hclust(c, method='mcquitty')},
                lmat=rbind( c(0, 3), c(2,1), c(0,4) ), lhei=c(0.25, 4, 0.25 ),                 
      )
      grab_grob()
    })
    
    grid.newpage()
    library(gridExtra)
    grid.arrange(grobs=gl, ncol=2, clip=TRUE)