9
votes

To draw arrows in ggplot, I use geom_segment and arrow=arrow(). I would like the arrow head size to match the segment width (or size). However, arrow does not recognize variables directly from the data argument in ggplot and one must specify data.frame containing the variable using the $ operator. This causes a disjunct between the values used for plotting the line and those used for plotting the arrow head (the largest arrow head can be on the thinest segment).

Example:

d <- structure(list(Process = structure(c(2L, 1L, 1L, 1L, 2L, 2L, 
1L, 1L, 2L, 1L, 2L), .Label = c("First", "Second"), class = "factor"), 
x.sink = c(1, 3, 1, 2, 2, 3, 3, 2, 2, 2, 2), y.sink = c(1, 
1, 1, 2, 2, 1, 1, 1, 1, 2, 2), x.source = c(2, 2, 2, 2, 2, 
2, 2, 1, 1, 1, 3), y.source = c(2, 2, 2, 1, 1, 1, 1, 1, 1, 
2, 1), offset = c(1, 1, 1, -1, -1, -1, -1, -1, -1, 1, -1), 
Std.Flux = c(0.179487179487179, 0.170940170940171, 0.944444444444444, 
0.0854700854700855, 0.726495726495726, 0.128205128205128, 
0.213675213675214, 0.213675213675214, 0.128205128205128, 
0.106837606837607, 1)), .Names = c("Process", "x.sink", "y.sink", 
"x.source", "y.source", "offset", "Std.Flux"), class = "data.frame", row.names = c(NA, 
-11L))


p <- qplot(data=d,
           #alpha=I(0.4),
           colour=Process,
           size=Std.Flux,
           xlim=c(0,4),
           ylim=c(0,3),
           x=x.source+as.numeric(Process)/10,
           y=y.source+as.numeric(Process)/10,
           xend=x.sink+as.numeric(Process)/10,
           yend=y.sink+as.numeric(Process)/10,
           geom="segment",
           arrow = arrow(type="closed",
                         length = unit(d$Std.Flux,"cm")))
print(p)

Disjunct arrow heads

Any suggestions?

2
i reckon it's an oversight; worth posting a feature request on github - baptiste
Voting to close - Reporting bug which must have been fixed in the last 8 years - not reproducible any more (see reprex in my answer) - tjebo

2 Answers

1
votes

Here's one way:

require(ggplot2)

df <- mtcars

arrow_pos <- data.frame(y = 250)

ggplot(df, aes(x=factor(cyl), y=mpg)) +
  geom_bar(width = .4, stat="identity", fill="darkblue")  +
  geom_segment(data=arrow_pos, 
               aes(x=1.526, xend=1.01, y=y + 90.02, yend=y + 0.25),
               arrow=arrow(length=unit(4.2, "mm")), lwd=2,
               color="black") +
  geom_segment(data=arrow_pos, 
               aes(x=1.525, xend=1.01, y=y + 90, yend=y + 0.25),
               arrow=arrow(length=unit(4, "mm")), lwd=1,
               color="gold2") +
  annotate("text", x=2.39, y=360, 
           label='This arrow points to the highest MPG.') +
  scale_y_continuous(limits = c(0,400)) +
  xlab('CYL') + ylab('MPG')

Output:

enter image description here

0
votes

Must have been fixed in the last 8 years :)

Here translated into a call to ggplot()

library(ggplot2)

ggplot(d, aes(colour=Process, size=Std.Flux)) +
  geom_segment(aes(x=x.source+as.numeric(Process)/10,
                   y=y.source+as.numeric(Process)/10,
                   xend=x.sink+as.numeric(Process)/10,
                   yend=y.sink+as.numeric(Process)/10),
                   arrow = arrow(type="closed",
                         length = unit(d$Std.Flux,"cm")))