在ggplot2中使用grconvertX/grconvertY

9
我正在尝试学习如何在ggplot中使用grconvertX/grconvertY。我最终的目标是通过将用户坐标转换为设备坐标,使用grid.text和grid.lines向ggplot2图形(以及可能的lattice)添加注释。我知道可以通过grobs实现,但我想知道是否有更简单的方法。
以下代码允许我将用户坐标传递到ndc坐标,并使用这些值来为图形添加grid.text注释。
graphics.off()      # close graphics windows   

library(grid)
library(gridBase)


test= data.frame(
  x = c(1,2,3),
  y = c(12,10,3),
  n = c(75,76,73)
  )

par(mar = c(13,5,2,3))

plot(test$y ~ test$x,type="b", ann=F)

for (i in 1:nrow(test))

{
  X=grconvertX(i , from="user", to="ndc")
  grid.text(x=X, y =0.2, label=paste("GRID.text at\nuser.x=", i, "\n", "ndc.x=", (signif( X, 5))   ) ) 
  grid.lines(x=c(X, X), y = c(0.28, 0.33) )
}
#add some code to save as PDF ...

输入图像描述

这段代码基于我之前的一篇文章中提到的解决方案:混合X和Y坐标系。你可以看到原始图表中的x坐标是如何转换为ndc的。这种方法的优点是可以使用设备坐标来表示Y。

我认为我可以轻松地在ggplot2(可能也包括lattice)中做同样的事情。

library(ggplot2)
graphics.off()      # close graphics windows   

qplot(x=x, y=y, data=test)+geom_line()+  opts(plot.margin = unit(c(1,3,8,1), "lines"))

for (i in 1:nrow(test))

{
  X=grconvertX(i , from="user", to="ndc")
  grid.text(x=X, y =0.2, label=paste("GRID.text at\nuser.x=", i, "\n", "ndc.x=", (signif( X, 5))   ) ) 
  grid.lines(x=c(X, X), y = c(0.28, 0.33) )
}

#add some code to save as PDF...

然而,它并没有正常工作。坐标似乎有点偏差。垂直线和文本与图表上的刻度标签不对应。有人可以告诉我如何修复吗?提前感谢您的帮助。 输入图像描述

提醒一下,我已经编辑了一些问题的格式,以便更好地符合代码高亮的“标准”使用。此外,在人们可能会快速复制粘贴的代码中最好不要包含删除用户工作区中所有对象的行。让读者确保他们处于一个干净的R会话中。 - joran
谢谢!我认为在一个干净的会话中工作会更容易。我不会再添加这段代码了。 - Max C
请注意,opts()已更改为theme(),有关更多信息,请参见Winston Chang的github - Dion Groothof
1个回答

12
grconvertXgrconvertY函数适用于基本图形,而ggplot2使用网格图形。一般而言,这两种不同的图形引擎不能很好地协同工作(尽管您已经演示了使用gridBase来帮助)。您的第一个示例可以工作,因为您从基本图形开始,所以用户坐标系存在于基础图形中,grconvertX将其转换。在第二种情况下,用户坐标系从未在基本图形中设置,因此它看起来可能使用默认坐标0,1,这些坐标与顶部视口坐标相似但并不完全相同,所以您会得到类似但不完全正确的结果(实际上我对您没有收到错误或警告感到惊讶)。
通常,在网格图形中,将坐标之间进行转换的等效方法是仅创建具有所需坐标系的新视口(或推入/弹出到具有正确坐标系的现有视口),然后在该视口中添加注释。
以下是一个示例,它创建了您的绘图,然后向下移动到包含主绘图的视口,创建了一个新视口,其尺寸相同但剪辑被关闭,x比例尺基于数据而y比例尺为0,1,然后相应地添加了一些文本:
library(ggplot2)
library(grid)

test= data.frame(   x = c(1,2,3),   y = c(12,10,3),   n = c(75,76,73)   )  

qplot(x=x, y=y, data=test)+geom_line()+  opts(plot.margin = unit(c(1,3,8,1), "lines"))  

current.vpTree()
downViewport('panel-3-4')
pushViewport(dataViewport( test$x, clip='off',yscale=c(0,1)))

for (i in 1:nrow(test))  {
    grid.text(x=i, y = -0.2, default.units='native',
        label=paste("GRID.text at\nuser.x=", i, "\n"   ) )
        grid.lines(x=c(i, i), y = c(-0.1, 0), default.units='native' )
 } 

这里的一个棘手问题是ggplot2没有将视口比例设置为与正在绘制的数据相匹配,而是自行进行转换。在这种情况下,基于x数据设置比例是有效的,但如果ggplot2做了一些花哨的事情,那么这可能不起作用。我们需要的是一种从ggplot2获取反变换坐标的方法,以便在调用grid.text时使用。


Greg:非常感谢!这是一个很好的解决方案。我将您的代码应用于另一个图形,看起来完全正常: https://dev59.com/Ymkv5IYBdhLWcg3wiRWo - Max C
1
+1 tikzDevice 提出了一些独创的想法来解决这个难题。他们定义了新的“虚拟” grobs,并将 geom_s 与之关联,其唯一目的是为外部(tikz 节点)对象提供精确的定位。我想知道这个想法是否可以推广。 - baptiste
1
请注意,opts()已更改为theme(),有关更多信息,请参见Winston Chang的github - Dion Groothof

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接