【问题标题】:How to tell if a plot is complete or not如何判断一个情节是否完整
【发布时间】:2013-08-06 07:25:28
【问题描述】:

更新:我问了 Paul Murrell(“最终老板”),他告诉我打开新页面的决定是在 src/library/graphics/src/graphics.cGNewPlot 做出的:

pGEDevDesc GNewPlot(Rboolean recording)

它有效地查看par(mfg)par(new) 来决定是否打开一个新页面。如何在附加包中进行测试?

使用纯 R 代码或一些 C 代码的解决方案是可以接受的。


knitr 使用 evaluate 包来评估 R 代码块,并捕获结果,包括绘图。简而言之,evaluate 调用 recordPlot() 以在每个代码表达式被评估后记录当前绘图的快照,以及在调用像 before.plot.newbefore.grid.newpage 这样的绘图钩子时(通常这发生在新绘图之前画了)。对于那些“卢克”,如果这还不够清楚,请use the source

创建快照后,我们需要决定是否保留它,因为在计算新表达式后快照可能不会更改,这与绘图无关。现在我的问题来了:当一个图包含子图(例如,pairs()coplot() 或基本 R 图形中的par(mfrow = c(2, 3)))时,我们不应该保留不完整的快照。在下面的示例中,应丢弃前三个图:

par(mfrow = c(2, 2))
plot(rnorm(10))
plot(rnorm(10))
plot(rnorm(10))
plot(rnorm(10))

为了实现这一点,我们将par("mfg")[1:2]par("mfg")[3:4] 进行比较(如您在源代码中所见),这在某些情况下效果很好,但不是全部,例如issue #25

layout(matrix(c(1,3,2,3), 2))
plot(rnorm(10))
plot(rnorm(10))
plot(rnorm(10))

现在我怎么知道情节在第 4 行之前不完整? mfg 技巧不再有效。

我一直在寻找这个问题的答案,如果有人能给我提示,我将不胜感激;更多详细信息在上面的两个链接中,如果有任何不清楚的地方,我可以澄清一下。我相信一定存在解决方案,因为所有的 R 设备都知道何时开始新的绘图屏幕或文件,不完整的绘图不会触发新的绘图屏幕或文件。

【问题讨论】:

  • 我真的认为无法确定情节是否完整,并且以后不会有 R 表达式可以进一步扩展。我在pander 中使用evals 函数(我使用它而不是evaluate 来做一些额外的事情)是用户可以“标记”带有前导+ 符号的行以包含在最后一个称为情节 - 这是一个非常不理想的解决方案,但我想不出更好的主意。更多详情:support.rapporter.net/entries/…
  • 定义布局并不一定意味着所有单元格最终都会被实际使用,不是吗?我可以想象一个单元格故意留空的情况。我认为如果有明确的答案,就不需要dev.off()
  • @daroczig 谢谢!我认为这确实不是最理想的。 @baptiste 你是对的;在所有单元格填满之前可以dev.off(),这对我来说不是问题
  • 大家好,这个问题不用再追究了。我得到了 R core 的官方支持。确定后我会发布答案。
  • 这是个好消息。非常期待看到您如何解决这个问题并获得对相关低级 C 函数的访问权限。

标签: r graphics knitr


【解决方案1】:

更新:现在在 R 3.0.2 中可用。


Paul Murrell 在他的recent commit 中,在par() 中添加了一个新的只读参数,名为page,它给出了TRUEFALSE,表示下一个情节是否需要打开一个新页面。

这是通过从GNewPlot() 复制一些代码实现的,目前仅在 R-devel 中可用。

【讨论】:

  • 现在在 R 3.0.2 中可用
【解决方案2】:

来自?par

 ‘mfg’ A numerical vector of the form ‘c(i, j)’ where ‘i’ and ‘j’
      indicate which figure in an array of figures is to be drawn
      next (if setting) or is being drawn (if enquiring).  The
      array must already have been set by ‘mfcol’ or ‘mfrow’.

因此,您似乎需要使用pairing functionpar("mfg")[1:2] 的初始值分配一个唯一ID,然后针对该键测试par("mfg")[1:2] 的后续值。例如,一个有效的配对是2**par("mfg")[1] * 3**par("mfg")[2]:

Pid <- function(ij, test.id=NA){
        mi <- ij[1]
        mj <- ij[2]
        ijd <- 2**mi * 3**mj
        if (!is.na(test.id)) ijd <- ijd == test.id
        return(ijd)
}

回到你的例子:

layout(matrix(c(1,3,2,3), 2))
x0 <- par("mfg")  # 2 1 2 2
id <- Pid(x0)     # 12
plot(rnorm(10))
x1 <- par("mfg")
p1 <- Pid(x1, id) # FALSE (layout is not full)
plot(rnorm(10))
x2 <- par("mfg")
p2 <- Pid(x2, id) # FALSE (layout is not full)
plot(rnorm(10))
x3 <- par("mfg")
p3 <- Pid(x3, id) # TRUE (layout is now full)
#
rbind(p1,p2,p3)
#    [,1]
#p1 FALSE
#p2 FALSE
#p3  TRUE

不过,我想如果没有最初的 id,你会很不走运。

【讨论】:

  • 谢谢!你给了我很好的启发!配对功能在这里并不重要;最重要的是最初的mfg;我可以简单地使用identical() 将后续的mfg 值与初始向量进行比较,我have done that,但我仍然认为这不是一个可靠的方法
猜你喜欢
  • 2011-11-19
  • 1970-01-01
  • 1970-01-01
  • 2013-01-14
  • 2013-09-29
  • 2013-11-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多