【问题标题】:How to create a pairs-plot (matrix-like plot) with `grid`?如何使用“网格”创建配对图(类似矩阵的图)?
【发布时间】:2013-07-27 18:32:30
【问题描述】:

我正在grid 中尝试我的第一步纯粹。作为练习,我想创建一个完全基于grid 的配对图(类似于pairs())。下面的函数myplotGrob 应该创建网格对象(grob;或gTree)并返回该对象。

我不确定 继续的最好方法是什么。应该使用哪些单位? (也试过"null"frameGrob 是用来设置布局的吗? (这是我从 Paul Murrell 的书中了解到的)我如何选择/调整视口才能获得所需的情节(到目前为止,我只看到一团糟)布局是要预先设置的还是它最好只是逐步“连接”其他面板以获得 (4, 4) 绘图矩阵?

require(grid)
require(mvtnorm)

set.seed(271)
X <- rmvnorm(1000, mean=1:4, sigma=diag(4:1)) # goal: draw this in a pairs plot

## auxiliary function
panel <- function(x, y) pointsGrob(x=x, y=y, name="panel", gp=gpar(), vp=NULL)

## creates and returns a gTree (class)
myplotGrob <- function(X, name=NULL, gp=NULL, vp=NULL)
{
    ## x-axis grob

    ## y-axis grob

    ## ...

    ## set up layout
    layout <- grid.layout(4, 4, # (4, 4) matrix
                          widths=rep(0.25, 4), heights=rep(0.25, 4),
                          default.units="npc")
    ## pushViewport(viewport(layout=layout)) # required???

    all <- frameGrob(layout=layout) # produces a gTree without children
    for(i in 1:4) {
        for(j in 1:4) {
            ## group grobs together
            gt <- gTree(X,
                        children=gList(panel(X[,i], X[,j])),
                        name=name, gp=gp, vp=vp, cl="myplotGrob")
            all <- placeGrob(all, gt, row=i, col=j)
        }
    }
    all
}

## draw the gTree
grid.myplot <- function(...) grid.draw(myplotGrob(...))

## call
grid.myplot(X)

更新

正如所要求的,这是我想到的原始问题的设计/布局(以上只是一个最小/学习示例)。以厘米为单位的单位只适合我(它们最终应该是“相对的”)。当然,面板的数量可能会有所不同。我希望所有部分都是网格对象,以便创建图形的函数将返回一个对象(不打印/绘图)。这样,每个部分都可以在之后进行修改。图形应显示维度为 5(或更小)的数组的结果:一个维度显示在行面板 [row.vars] 中,一个维度显示在列面板 [col.vars] 中,一个维度显示在每个面板的 x 轴上 [ xvar],每个面板可以包含 2 个不同维度的数组(因颜色和线型而异)[我在图中使用了dn]。如果当然,如果数组是四维的,那么上面设计的第 8 行应该是缺失的。我可以通过网格构建布局,但整个问题是如何从那里继续。这就是我想用上面的“最小示例”表达的内容。

【问题讨论】:

  • 我的建议:不要使用 frameGrobs 和 co;它们非常慢,而且不是很有用。在我看来,gtable 包提供了一个更好的选择。
  • 另外,你为什么要重新发明 lattice 和 ggplot2 已经做得很好的东西?你有什么特定的功能吗?
  • 嗨巴蒂斯特,感谢您的帮助。是的,我们有(实际上是几个)新功能。理想情况下,我们不想依赖另一个包(grid 除外),这就是我们从头开始的原因(学习grid 也很好,所以我们把它当作练习:-))。如果不使用frameGrobs(这是我从保罗的书中所理解的),我们还能使用什么?理想情况下,我只想看一个如何使用网格的最小(但有效)示例。
  • grid.multipanel() 可以给你一些想法,我猜。除非您更准确地描述您希望在目标图中具有哪些功能(关于轴、面板之间的间距、图例、条带、多层数据……),否则很难给出有意义的答案。可以的话画一下有许多不同的方法来产生一个情节,想出一个最佳的设计并不是一件容易的事(这可能是每个绘图程序似乎都在重新发明轮子的原因)。
  • @baptiste 我不同意。 ggplot2 和 lattice 并不能解决每个人的问题,有些用户可能还想更深入地控制他们的图形。

标签: r r-grid


【解决方案1】:

我认为您可以将任务分为两个主要部分,例如 grid.panel()grid.multipanel() 中的基本示例

1- 构建一个生成单个面板的函数,以 gTree 形式返回。您需要弄清楚所有参数,即限制、轴、颜色、形状、网格、坐标……您最终可能会重写晶格面板函数和轴,

grid.newpage()
grid::grid.panel(vp=viewport(width=0.8, height=0.8))

2- 在布局中组装面板。这 使用 gtable 更容易(也更干净),

library(gtable)

grid.newpage()
lg <- replicate(16, grobTree(rectGrob(), pointsGrob()), simplify=FALSE)

gt <- gtable_matrix("pairs", grobs=matrix(lg, ncol=4),
                    widths=unit(rep(1, 4), "null"),
                    heights=unit(rep(1, 4), "null"))

gt <- gtable_add_col_space(gt, width=unit(0.5,"line"))
gt <- gtable_add_row_space(gt, height=unit(0.5,"line"))
gt <- gtable_add_padding(gt, padding=unit(1,"line"))

grid.draw(gt)

如果您想从头开始构建所有内容,我认为您最终也将不得不重新发明 gtable 的大部分内容。

【讨论】:

  • 很高兴您看到了“两步”方法,这正是我想要的。理想情况下,面板功能由用户提供(例如,箱线图或 x-y 图)。然后将基本的类似矩阵的结构放在它周围。确实,gtable 看起来很干净。看来我得仔细想想了。让我现在接受答案,然后再回来提出后续问题,以防我们遇到它们(我相信我们会:-))。非常感谢,不知何故我知道在真正开始之前先问问专家会很好:-)
【解决方案2】:

这是一个类似于 grid.multipanel() 的尝试,但返回一个 gTree,并且更具体到您的配对图,

require(grid)
require(mvtnorm)

set.seed(271)
X <- rmvnorm(100, mean=1:4, sigma=diag(4:1)) # goal: draw this in a pairs plot

panelGrob <- function(x=runif(10, -10, 10), y=runif(10, -10, 100), ...,
  xlim = range(x), ylim=range(y),
  axis.x=TRUE, axis.y=TRUE){
  xx <- pretty(x) ; yy <- pretty(y)
  xx <- xx[xx <= xlim[2] & xx >= xlim[1]]
  yy <- yy[yy <= ylim[2] & yy >= ylim[1]]

  r <- rectGrob()
  dvp <- dataViewport(xData=xx, yData=yy)
  p <- pointsGrob(x, y, pch=".", gp=gpar(col="red"), default.units="native",
                  vp = dvp)

  ax <- if(axis.x) xaxisGrob(at=xx, vp=dvp) else nullGrob()
  ay <- if(axis.y) yaxisGrob(at=yy, vp=dvp) else nullGrob()

  grobTree(r, ax, ay, p, ...)
}

grid.panel <- function(...)
  grid.draw(panelGrob(...))

grid.newpage()
grid.panel(vp=viewport(width=0.8, height=0.8))


pairsGrob <- function(X, ..., name=NULL, gp=NULL, vp=NULL){

  N <- NCOL(X)
  layout <- grid.layout(N+1, N+1, 
                        widths=unit(c(2, rep(1, N)), c("lines", rep("null", N))), 
                        heights = unit(c(rep(1, N), 2), c(rep("null", N), "lines")))


  wrap <- function(ii, jj, ...){
    panelGrob(X[,ii], X[,jj], ..., axis.x= ii == N, axis.y = jj == 1,
              vp=viewport(layout.pos.row=ii, layout.pos.col=jj+1))
  }

  rowcol <- expand.grid(ii=seq_len(N), jj=seq_len(N))
  gl <- mapply(wrap, ii=rowcol[,"ii"], jj=rowcol[,"jj"], MoreArgs=list(...),
               SIMPLIFY=FALSE)

  gTree(children=do.call(gList, gl), vp=viewport(layout=layout))
}

grid.pairs <- function(...) grid.draw(pairsGrob(...))

grid.newpage()
grid.pairs(X, xlim=c(-10,10), ylim=c(-10,10))

许多问题已经很明显了:i) 在布局中添加间距、跟踪正确的视口很麻烦; ii) 面板功能的大多数参数都是硬连线的(点形状、颜色、网格、轴标签……),为复杂性的爆炸做好准备,如args(lattice::panel.xyplot); iii)轴的范围应该在一行/列中匹配,这需要考虑将数据正确分组(ggplot2或lattice中的分面); iv) 传说是在网格中重新发明的另一件事;五)...

【讨论】:

  • 亲爱的巴蒂斯特,非常感谢,这一切都很有趣。根据上述设计,我们已经拥有非网格形式的主情节,并且确实面临用户可能想要拥有的大量事物的“爆炸”问题......我们的想法是制作函数返回一个gTree,以便用户在需要时仍然可以修改它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-11
  • 2014-05-24
  • 2021-01-09
  • 1970-01-01
  • 1970-01-01
  • 2019-07-11
相关资源
最近更新 更多