R:我怎么画一条有多个箭头的线?

时间:2011-08-01 03:19:18

标签: r plot

我想知道是否有人可以帮我在R中用多个箭头绘制线条,如下所示:

---> ---> ---> --->

提前致谢!

5 个答案:

答案 0 :(得分:5)

基于对原始问题的澄清,我认为应该考虑一般性答案

  • 计算由(x,y)点指定的断裂曲线的总长度

  • 分开中间段以确保箭头之间的曲线长度相等

  • 处理细微的细节,例如初始“阶段”,终点,箭头是否应该跟着一个薄的空间等等。

arrows

下面粗略地抨击它。

arrowLine <- function(x, y, N=10, ...){
  lengths <- c(0, sqrt(diff(x)^2 + diff(y)^2))
  l <- cumsum(lengths)
  tl <- l[length(l)]
  el <- seq(0, to=tl, length=N+1)[-1]

  plot(x, y, t="l", ...)

  for(ii in el){

    int <- findInterval(ii, l)
    xx <- x[int:(int+1)]
    yy <- y[int:(int+1)]

    ## points(xx,yy, col="grey", cex=0.5)

    dx <- diff(xx)
    dy <- diff(yy)
    new.length <- ii - l[int]
    segment.length <- lengths[int+1]

    ratio <- new.length / segment.length

    xend <- x[int] + ratio * dx
    yend <- y[int] + ratio * dy
    points(xend,yend, col="white", pch=19)
    arrows(x[int], y[int], xend, yend, length=0.1)

}

}

set.seed(123)
x = sort(c(0, runif(200, 0,2* pi), 2*pi))
y=sin(x)

arrowLine(x, y, N=20)

答案 1 :(得分:3)

有一种偷偷摸摸的方式可以做到这一点,而不必绘制一堆线段或箭头 从上面的xy数据开始:

plot(x, y, t='l')

然后使用一些预制例程计算从x[1]y[1]x[2]y[2]等的局部斜率。将斜率转换为以度为单位的角度,然后(调用斜率矢量angslopes

text(x, y, labels=">", srt=angslopes)  # throws error

抱歉,这不起作用,因为据我所知,srt必须是单个值。所以:

diflen <- length(x)-1
sapply(1:diflen, function(xind) text(x[xind+1], y[xind+1], labels='>', cex=2.5, srt=angslopes[xind]))

格子包中可能有更简单的方法。

这种方法具有美观的优点,允许您通过par(cex)指定箭头大小以及颜色 - 可能与线条颜色不同,甚至沿曲线变化。

答案 2 :(得分:2)

正如约兰所说,arrows

 x=cos( seq(0, pi, by=pi/8)  )
 y=sin( seq(0, pi, by=pi/8))
 plot(1,1, ylim=range(y), xlim=range(x))
 arrows(x[-length(x)],y[-length(y)], x[-1],y[-1])

如果要绘制具有相等长度规格的直线多箭头曲线,请使用此函数:

multarrows <- function(x0,y0, x1,y1,n_arr, ...) {x<- seq(x0,x1, length=n_arr+1)
             y<-seq(y0,y1, length=n_arr+1)
             arrows(x[-length(x)],y[-length(y)], x[-1],y[-1], ...) }
plot(0,0, xlim=c(0,2), ylim=c(0,11)); multarrows(0,0, 1,10, 10)

enter image description here

答案 3 :(得分:2)

Simulair to DWin这就是我提出的:

arrowLine <- function(x0,y0,x1,y1,nArrow=1,...)
{
  lines(c(x0,x1),c(y0,y1),...)
  Ax=seq(x0,x1,length=nArrow+1)
    Ay=seq(y0,y1,length=nArrow+1)
  for (i in 1:nArrow)
  {
    arrows(Ax[i],Ay[i],Ax[i+1],Ay[i+1],...)
  }
}

基本上它与一行中的几个箭头重叠,但确实得到了所需的结果(我假设是直线):

plot(0:1,0:1)
arrowLine(0,0,1,1,4)

Multiple arrows on a line

真正棘手的部分是让箭头到达点的边缘而不是中心。这需要吗?

答案 4 :(得分:1)

我想我会在这里添加一个基本的R解决方案,该解决方案会将箭头计算为分段。有创建新图或向现有图添加箭头的版本。较长的段分为较短的段:

add_arrows <- function(x, y, ...)
{
  # Ensure equal lengthed vectors
  min_len <- min(length(x), length(y))
  x  <- x[seq(min_len)]
  y  <- y[seq(min_len)]

  # Calculate y:x ratio
  yx_ratio <- 3*(max(y) - min(y)) / (max(x) - min(x))

  # Create start and end points
  x1 <- x[-length(x)]
  y1 <- y[-length(y)]
  x2 <- x[-1]
  y2 <- y[-1]

  # Length and angle of line segments
  theta <- atan((y2 - y1)/(x2 - x1))
  seg_lengths <- sqrt((x2 - x1)^2 + (y2 - y1)^2)

  # Break long segments into shorter segments
  long <- which(seg_lengths > (2 * min(seg_lengths)))
  if(length(long) > 0)
  {
    n_segs <- floor(seg_lengths[long] / (1.5 * min(seg_lengths)))

    for(i in seq_along(long))
    {
      xs <- x1[long[i]] + (0:n_segs[i]) * (x2[long[i]] - x1[long[i]]) / n_segs[i]
      ys <- y1[long[i]] + (0:n_segs[i]) * (y2[long[i]] - y1[long[i]]) / n_segs[i]
      x1 <- c(x1, xs[-length(xs)])
      x2 <- c(x2, xs[-1])
      y1 <- c(y1, ys[-length(ys)])
      y2 <- c(y2, ys[-1])
      theta <- c(theta, rep(theta[long[i]], length(xs) - 1))
    }

    x1 <- x1[-long]; x2 <- x2[-long]; y1 <- y1[-long]; y2 <- y2[-long];
    theta <- theta[-long]
  }
  # Arrow head length and width
  len <- sqrt((max(y) - min(y))^2 + (max(x) - min(x))^2)/ 20
  wid <- len * 0.1


  # Calculate arrow heads
  zx  <- x2 - len * cos(theta) * sign(x2 - x1)
  zy  <- y2 - len * sin(theta) * sign(x2 - x1)
  ax1 <- zx + wid * sin(theta) * sign(x2 - x1)
  ax2 <- zx - wid * sin(theta) * sign(x2 - x1)
  ay1 <- zy - wid * cos(theta) * sign(x2 - x1) * yx_ratio
  ay2 <- zy + wid * cos(theta) * sign(x2 - x1) * yx_ratio

  df <- data.frame(x1  = x1 + 0.1 * (x2 - x1),
                   y1  = y1 + 0.1 * (y2 - y1),
                   x2  = x2 - 0.5 * len * cos(theta) * sign(x2 - x1),
                   y2  = y2 - 0.5 * len * sin(theta) * sign(x2 - x1),
                   ax1 = ax1, ay1 = ay1, ax2 = ax2, ay2 = ay2)

  # Draw segments
  segments(df$x1, df$y1, df$x2,  df$y2,  col = "red", lwd = 2)
  segments(df$x2, df$y2, df$ax1, df$ay1, col = "red", lwd = 2)
  segments(df$x2, df$y2, df$ax2, df$ay2, col = "red", lwd = 2)
}

这允许您绘制箭头作为绘制的基础:


plot_arrows <- function(x, y, ...)
{
  plot(x, y, col = "white", ...)
  add_arrows(x, y, ...)
}

所以现在您可以这样做:

set.seed(69)

x <- 1:10
y <- sample(10)
plot(x, y)
add_arrows(x, y)

reprex package(v0.3.0)于2020-02-29创建