假设我们在R中有一个多面板图,使用layout()
创建。我想从一个面板中的指定点到另一个面板中的指定点绘制一个箭头。因此,箭头跨越布局的面板。箭头的起点在其面板的坐标中指定,箭头的终点在目标面板的坐标中指定。
作为一个最小的例子,考虑一下:
layout( matrix( 1:2 , nrow=2 ) )
plot( x=c(1,2) , y=c(1,2) , main="Plot 1" )
plot( x=c(10,20) , y=c(10,20) , main="Plot 2" )
# I want to make an arrow
# from point c(x=1.2,y=1.2) in Plot 1
# to point c(x=18,y=18) in Plot 2
我已经搜索了实现此目的的方法,但没有找到任何东西。感谢您提供解决方案或指示。
答案 0 :(得分:2)
(我将上一个答案保留在此以下,但鉴于您的意见,这种更具程序性的方式会更好。)
诀窍是知道如何从"用户"坐标到总体设备的坐标。这可以通过grconvertX
和*Y
来完成。我在这里做了一些草率的辅助功能,虽然它们几乎没有必要。
user2ndc <- function(x, y) {
list(x = grconvertX(x, 'user', 'ndc'),
y = grconvertY(y, 'user', 'ndc'))
}
ndc2user <- function(x, y) {
list(x = grconvertX(x, 'ndc', 'user'),
y = grconvertY(y, 'ndc', 'user'))
}
为了将魔术常数排除在代码之外,我将预定义您的兴趣点:
pointfrom <- list(x = 1.2, y = 1.2)
pointto <- list(x = 18, y = 18)
在情节仍然是最新的情况下,从'user'
转换为'ndc'
非常重要;一旦从图1切换到2,坐标就会改变。
layout( matrix( 1:2 , nrow=2 ) )
情节1。
plot( x=c(1,2) , y=c(1,2) , main="Plot 1" )
points(y~x, data=pointfrom, pch=16, col='red')
ndcfrom <- with(pointfrom, user2ndc(x, y))
情节2。
plot( x=c(10,20) , y=c(10,20) , main="Plot 2" )
points(y~x, data=pointto, pch=16, col='red')
ndcto <- with(pointto, user2ndc(x, y))
正如我之前所做的那样(远远低于此处),我重新映射了下一个绘图命令将在其上发生的区域。在幕后,layout
正在做这样的事情。 (可以使用par(fig=..., new=T)
完成一些巧妙的技巧,包括将一个绘图覆盖在其中,周围或几乎不与另一个重叠。)
par(fig=c(0:1,0:1), new=TRUE)
plot.new()
newpoints <- ndc2user(c(ndcfrom$x, ndcto$x), c(ndcfrom$y, ndcto$y))
with(newpoints, arrows(x[1], y[1], x[2], y[2], col='green', lwd=2))
我可能已经能够避免从ndc2user
回到当前用户点的ndc
转换,但是这会使用边距和轴扩展以及类似的东西,所以我选择了不要。
转换点可能在最后一个重叠图的用户点区域之外,在这种情况下它们可能被屏蔽。要解决此问题,请将xpd=NA
添加到arrows
(或之前的par(xpd=NA)
)。
好的,想象一下你希望能够在layout
完成后确定任何绘图的坐标。这是一个更复杂的实现,目前支持您要求的内容。唯一的要求是你在每个(有意义的)情节之后调用NDC$add()
。例如:
NDC$reset()
layout(matrix(1:4, nrow=2))
plot(1)
NDC$add()
plot(11)
NDC$add()
plot(21)
NDC$add()
plot(31)
NDC$add()
with(NDC$convert(1:4, c(1,1,1,1), c(1,11,21,31)), {
arrows(x[1], y[1], x[2], y[2], xpd=NA, col='red')
arrows(x[2], y[2], x[3], y[3], xpd=NA, col='blue')
arrows(x[3], y[3], x[4], y[4], xpd=NA, col='green')
})
可在此处找到来源:https://gist.github.com/r2evans/8a8ba8fff060bade13bf21e89f0616c5
一种方法是使用par(fig=...,new=TRUE)
,但它不会保留您的坐标
layout(matrix(1:4,nr=2))
plot(1)
plot(1)
plot(1)
plot(1)
par(fig=c(0,1,0,1),new=TRUE)
plot.new()
lines(c(0.25,0.75),c(0.25,0.75),col='blue',lwd=2)
如果你对点的末端有更好的(非任意的)控制,你可能更有可能使用它,这里有一个技巧,让你可以更好地控制点。如果我使用它,请将左上角与右下角连接起来:
p <- locator(2)
str(p)
# List of 2
# $ x: num [1:2] 0.181 0.819
# $ y: num [1:2] 0.9738 0.0265
然后代替上面的lines
,我用这个:
with(p, arrows(x[1], y[1], x[2], y[2], col='green', lwd=2))
我得到了
(这张图片和p
中的值说明了坐标的不同。使用par(fig=...,new=T);plot.new();
时,坐标返回
par('usr')
# [1] -0.04 1.04 -0.04 1.04
尝试解决此问题可能有些诡计(例如,如果您需要自动执行此步骤),但这可能非常重要(并且不够健壮)。