0

I'm using annotation_custom to make a custom legend with arrows.

Unfortunately, all arrows seem to have a downward angle (heading South-West or North-East) and I'm striving to make an upward arrow (heading North-West).

Here is a reproducible example:

library(ggplot2)
library(grid)
x=ggplot() +
  geom_blank() +
  geom_rect(aes(xmin=1, xmax=2,
                ymin=1, ymax=2)) +
  coord_fixed(clip="off") #a plain old nice grey rectangle

my_arrow = linesGrob(arrow=arrow(type="open", ends="first", length=unit(4,"mm")))
x + annotation_custom(my_arrow, xmin=1.5,xmax=2.2, ymin=1.5,ymax=1.25) #South-West :-)
x + annotation_custom(my_arrow, xmin=1.5,xmax=2.2, ymin=1.25,ymax=1.5) #Also South-West :-(

How can I construct such an arrow?

camille
  • 16,432
  • 18
  • 38
  • 60
Dan Chaltiel
  • 7,811
  • 5
  • 47
  • 92
  • You set `ends = "first"`, so the starting point has the arrow. Is that not what you wanted? – camille Feb 06 '20 at 16:07
  • @camille yes this is what I wanted. Setting it to "last" will make a North-East arrow, which is not my point. – Dan Chaltiel Feb 06 '20 at 16:13
  • It seems like `annotation_custom` doesn't really fit the situation well, since you're tied to xmin and xmax which won't take into account the direction you want. `annotate("segment")` might work better, since x and xend imply a direction. With the 2 sets of coordinates you have here, you the first to point southwest and the second to point northwest, right? – camille Feb 06 '20 at 16:20
  • @camille great, this works wonders! Could you copy that to an answer so I can close this question as accepted? – Dan Chaltiel Feb 07 '20 at 08:58

1 Answers1

0

annotation_custom seems to be tied to min & max coordinates like you would get from rectangles or images. For an arrow to make sense, it needs something to interpret as a direction. I'm switching to annotate with a segment geom, and saving the arrow for reusability.

my_arrow <- arrow(type = "open", ends = "first", length = unit(4, "mm"))

x +
  annotate("segment", x = 1.5, xend = 2.2, y = 1.5, yend = 1.25, arrow = my_arrow) +
  annotate("segment", x = 1.5, xend = 2.2, y = 1.25, yend = 1.5, arrow = my_arrow)

Since annotate doesn't have a data argument, you can't (AFAIK) map along data frame variables with aes, but you can give it vectors to tighten up into a single call.

x +
  annotate("segment", x = 1.5, xend = 2.2, y = c(1.5, 1.25), yend = c(1.25, 1.5), arrow = my_arrow)
# same output

Edit to add: based on the comment, it might make sense to put the segment coordinates in a data frame so you can also refer to them for placing labels.

coords <- tibble::tribble(
  ~x,  ~xend, ~y,   ~yend, ~lbl,
  1.5, 2.2,   1.5,  1.25,  "Still a square",
  1.5, 2.2,   1.25, 1.5,   "This is a square"
)

x +
  annotate("segment", x = coords$x, xend = coords$xend, y = coords$y, yend = coords$yend, arrow = my_arrow) +
  geom_text(aes(label = lbl, x = xend, y = yend), data = coords, hjust = 0)

camille
  • 16,432
  • 18
  • 38
  • 60
  • The goal was to put a "this is a grey square" annotation at the other end of the arrow. Looks really nice on my plot! – Dan Chaltiel Feb 07 '20 at 15:23
  • Okay, that makes sense now. If there's more you need to do with the arrows' coords, it might be helpful to put them in a data frame – camille Feb 07 '20 at 15:25