I was wondering if anyone could help me plot lines in R with multiple arrows in them, like this:
--->--->--->--->
Thanks in advance!
I thought I would add a base R solution here that calculates the arrow heads as segments. There are versions to create a new plot or add arrows to an existing plot. Longer segments are split into shorter ones:
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)
}
This allows you to plot arrows as the basis of your plot:
plot_arrows <- function(x, y, ...)
{
plot(x, y, col = "white", ...)
add_arrows(x, y, ...)
}
So now you can do:
set.seed(69)
x <- 1:10
y <- sample(10)
plot(x, y)
add_arrows(x, y)

Created on 2020-02-29 by the reprex package (v0.3.0)