将多个复杂图作为面板组合在一个图形中 [英] Combining multiple complex plots as panels in a single figure

查看:74
本文介绍了将多个复杂图作为面板组合在一个图形中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

通过使用layoutpar(mfrow=...),可以将多个简单图作为面板组合成一个图形.但是,更复杂的图倾向于在内部设置自己的面板布局,从而使其无法用作面板.有没有一种方法可以创建嵌套的布局并将复杂的图形封装到单个面板中?

Multiple simple plots can combined as panels in a single figure by using layout or par(mfrow=...). However, more complex plots tend to setup their own panel layout internally disabling them from being used as panels. Is there a way to create a nested layout and encapsulating a complex plot into a single panel?

我觉得grid软件包可以完成此操作,例如通过将面板绘制在单独的视口中,但还无法弄清楚该怎么做.这是一个演示问题的玩具示例:

I have a feeling the grid package can accomplish this, e.g. by ploting the panels in separate viewports, but haven't been able to figure out how. Here is a toy example to demonstrate the problem:

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`?

@alittleboy提出的原始问题

我使用gplots包中的heatmap.2函数来生成热图.这是单个热图的示例代码:

Original question by @alittleboy

I use the heatmap.2 function in the gplots package to generate heatmaps. Here is a sample code for a single heatmap:

library(gplots)
row.scaled.expr <- matrix(sample(1:10000),nrow=1000,ncol=10)
heatmap.2(row.scaled.expr, 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(row.scaled.expr),                 
          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 ),                 
)

但是,由于我想在一个图中比较多个热图,因此我使用par(mfrow=c(2,2)),然后调用heatmap.2四次,即

However, since I want to compare multiple heatmaps in a single plot, I use par(mfrow=c(2,2)) and then call heatmap.2 four times, i.e.

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 ),                 
)

但是,结果不是在单个图中有四个热图,而是四个单独的热图.换句话说,如果使用pdf()输出结果,则文件为四页而不是一页.我是否需要在某处更改任何参数?非常感谢!

However, the result is NOT four heatmaps in a single plot, but four separate heatmaps. In other words, if I use pdf() to output the result, the file is four pages instead of one. Do I need to change any parameters somewhere? Thank you so much!

推荐答案

好的.我想这个问题已经坐了很长时间了,应该写下很长的答案.

Okay. I suppose this question has been sitting unanswered for enough time that the long answer should be written up.

最棘手的图形问题的答案是(如@backlin所建议的)原始使用'grid'软件包.许多预构建的图形包会覆盖所有当前视口并绘制设备设置,因此,如果您想以一种非常特定的方式完成某些工作,则必须自己构建它.

The answer to most difficult graphics issues is (as @backlin suggests) the raw use of the 'grid' package. Many prebuilt graphics packages override all current viewports and plot device settings, so if you want something done a very specific way, you have to build it yourself.

我建议拿起Paul Murrell的书"R Graphics",并翻阅"grid"软件包的这一章.这是一本非常有用的疯狂书,而且一直在我的桌子上摆放一本书.

I recommend picking up Paul Murrell's book "R Graphics" and going over the chapter on the 'grid' package. It's a crazy useful book, and a copy sits on my desk all the time.

关于您的热图,我写了一个快速入门,可以帮助您快速入门.

For your heatmap, I've written up a quick primer that will get you started quickly.

要了解的功能

  • grid.newpage()这将初始化绘图设备.无需参数即可使用.
  • grid.rect()这将绘制一个矩形.您的热图基本上只是一组巨大的彩色矩形,因此这将占图形的大部分.它的工作原理如下:grid.rect(x=x_Position, y=y_Position, width=width_Value, height=height_Value, gp=gpar(col=section_Color, fill=section_Color), just=c("left", "bottom"), default.units="native")'just'参数指定矩形的哪个点将位于您指定的(x,y)坐标上.
  • grid.text()这将绘制文本.它的工作方式如下:grid.text("Label Text", x_Value, y_Value, gp=gpar(col=color_Value, cex=font_Size), just=c("right","center"), rot=rot_Degrees, default.units="native")
  • grid.lines()这画了一条线.它的工作方式如下:grid.lines(c(x_Start,x_End), c(y_Start, y_End), gp=gpar(col=color_Value), default.units="native")
  • dataViewport()这定义了绘图窗口的属性,网格"称为视口".像这样使用它:pushViewport(dataViewport(xData=x_Data, yData=y_Data, xscale=c(x_Min, x_Max), yscale=c(y_Min, y_Max), x=x_Value, y=y_Value, width=width_Value, height=height_Value, just=c("left","center")))这里有一些需要注意的地方……请参阅视口的更详细说明.
  • pushViewport()这用于初始化veiwport.您可以将其包装在视口定义周围,以实际执行视口,如下所示:pushViewport(dataViewport([stuff in here]))
  • popViewport()这样可以最终确定视口,并使您在视口层次结构中上移一层.请参阅视口的更详细说明.
  • grid.newpage() This initializes the plotting device. Use it without parameters.
  • grid.rect() This draws a rectangle. Your heatmap is basically just a giant set of colored rectangles, so this will be bulk of your graphic. It works like so: grid.rect(x=x_Position, y=y_Position, width=width_Value, height=height_Value, gp=gpar(col=section_Color, fill=section_Color), just=c("left", "bottom"), default.units="native") The 'just' argument specifies which point of the rectangle will sit on your specified (x, y) coordinates.
  • grid.text() This draws text. It works like so: grid.text("Label Text", x_Value, y_Value, gp=gpar(col=color_Value, cex=font_Size), just=c("right","center"), rot=rot_Degrees, default.units="native")
  • grid.lines() This draws a line. It works like so: grid.lines(c(x_Start,x_End), c(y_Start, y_End), gp=gpar(col=color_Value), default.units="native")
  • dataViewport() This defines the attributes of a plotting window, which 'grid' refers to as a "viewport." Use it like so: pushViewport(dataViewport(xData=x_Data, yData=y_Data, xscale=c(x_Min, x_Max), yscale=c(y_Min, y_Max), x=x_Value, y=y_Value, width=width_Value, height=height_Value, just=c("left","center"))) There is some stuff to keep in mind here... see the more detailed explanation of viewports.
  • pushViewport() This is used to initialize a veiwport. You wrap this around a viewport definition to actually execute the viewport, like so: pushViewport(dataViewport([stuff in here]))
  • popViewport() This finalizes a viewport and moves you up one level in the hierarchy of viewports. See the more detailed explanation of viewports.

概述中的视口

视口是临时绘制空间,用于定义在何处以及如何绘制网格"对象.视口中的所有内容均相对于相对绘制.如果旋转视口,则内部的所有内容都会旋转.视口可以嵌套,可以重叠并且几乎无限灵活,但有一个例外:它们始终是矩形.

Viewports are temporary drawing spaces that define where and how 'grid' objects will be drawn. Everything inside the viewport is drawn relative to the viewport. If the viewport is rotated, everything inside will be rotated. Viewports can be nested, can overlap, and are almost infinitely flexible, with one exception: they are always a rectangle.

最初使很多人困惑的是坐标系.每个视口,包括初始的"grid.newpage()"视口,在x和y轴上都从0变为1.原点(0,0)是最左下角,最大值(1,1)是最右上角.这是"npc"单位制,所有没有指定单位的东西都可能最终会根据此系统绘制.这对您来说意味着两件事:

Something that messes a lot of people up initially is the coordinate system. Every viewport, including the initial 'grid.newpage()' viewport, goes from 0 to 1 on both the x and y axes. The origin (0,0) is the far lower left corner, and the max (1,1) is the far upper right corner. This is the "npc" unit system, and everything that doesn't have a set of units specified will likely end up being drawn according to this system. This means two things for you:

  1. 指定视口大小和位置时,请使用"npc"系统.只需假设您的视口必须使用"npc"坐标,就可以节省很多麻烦.这意味着如果我要彼此相邻绘制两个图,则两个视口的定义将类似于:
    • viewport(x=0, y=0, width=0.5, height=1, just=c("left","lower"))
    • viewport(x=0.5, y=0, width=0.5, height=1, just=c("left","lower"))
  1. Use the "npc" system when specifying viewport sizes and locations. Just assume that your viewports have to use the "npc" coordinates, and you'll save yourself a LOT of hassle. This means if I want to draw two plots next to each other, the definitions for the two viewports would look something like:
    • viewport(x=0, y=0, width=0.5, height=1, just=c("left","lower")) and
    • viewport(x=0.5, y=0, width=0.5, height=1, just=c("left","lower"))

可以直接导航和写入视口,但是除非您执行非常自动化的操作,否则指定视口,在视口内绘制然后弹出"(完成)视口会更加容易.这将使您返回到父视口,并且您可以从下一个视口开始.弹出每个视口是一种无杂乱的方法,并且可以满足大多数目的(并使其更易于调试!).

Viewports can be navigated and written to directly, but unless you're doing something very automated, it is easier to specify a viewport, draw inside it, and then "pop" (finalize) the viewport. This returns you to the parent viewport, and you can start on the next viewport. Popping each viewport is a clutter-free approach and will suit most purposes (and make it easier to debug!).

在绘制图形时,"dataViewport"功能非常重要.这是一种特殊的视口,只要您告诉它所使用的数据,即可为您处理所有坐标和比例.这是我用于任何绘图区域的图形.刚开始使用"grid"软件包时,我调整了所有值以适合"npc"坐标系,但这是一个错误!只要您记得为每个绘图项目使用本机"单位,"dataViewport"功能就可以轻松完成.

The 'dataViewport' function is all important when plotting a graph. This is a special type of viewport that handles all of the coordinates and scales for you, as long as you tell it what data you are using. This is the one I use for any plotting area. When I first started using the 'grid' package, I adjusted all of my values to fit the "npc" coordinate system, but that was a mistake! The 'dataViewport' function makes is all easy as long as you remember to use the "native" units for each drawing item.

免责声明

数据可视化是我的强项,而且我不介意花半天的时间编写好视觉效果的脚本. 网格"程序包使我可以比发现的任何其他东西更快地创建非常复杂的视觉效果.我将视觉效果编写为功能脚本,因此可以快速加载各种数据.我再开心不过了.

Data visualization is my forte, and I don't mind spending half a day scripting up a good visual. The 'grid' package allows me to create quite sophisticated visuals faster than anything else I found. I script up my visuals as functions, so I can load various data quickly. I couldn't be happier.

但是,如果您不喜欢编写脚本,那么网格"将成为您的敌人.另外,如果您认为半天的时间对于视觉效果来说太长了,那么网格"对您的帮助就不会太多.众所周知的"ggplot2"软件包是大多数人都喜欢的软件包,尽管我个人认为它没有用,但我还是由衷地推荐它.

However, if you don't like to script things, 'grid' will be your enemy. Also, if you consider half a day to be too much time for a visual, then 'grid' won't help you too much. The (in)famous 'ggplot2' package is what most people settle on, and I heartily recommend it, even though I don't personally find it useful.

如果有人想帮助学习网格"图形,我非常乐于帮助教书.它彻底改变了我创建快速,智能和美观数据可视化效果的能力.

If someone wants help learning 'grid' graphics, I'm more than willing to help teach. It has completely revolutionized my ability to create fast, intelligent, and good-looking data visuals.

这篇关于将多个复杂图作为面板组合在一个图形中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆