如何在多面板图的面板上绘制箭头?

时间:2018-03-24 13:01:23

标签: r

假设我们在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

我已经搜索了实现此目的的方法,但没有找到任何东西。感谢您提供解决方案或指示。

1 个答案:

答案 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))。

enter image description here

广义

好的,想象一下你希望能够在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

enter image description here

上一个答案

一种方法是使用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)

enter image description here

如果你对点的末端有更好的(非任意的)控制,你可能更有可能使用它,这里有一个技巧,让你可以更好地控制点。如果我使用它,请将左上角与右下角连接起来:

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

我得到了

enter image description here

(这张图片和p中的值说明了坐标的不同。使用par(fig=...,new=T);plot.new();时,坐标返回

par('usr')
# [1] -0.04  1.04 -0.04  1.04

尝试解决此问题可能有些诡计(例如,如果您需要自动执行此步骤),但这可能非常重要(并且不够健壮)。