- Notifications
You must be signed in to change notification settings - Fork1
mdhall272/ggarchery
Folders and files
| Name | Name | Last commit message | Last commit date | |
|---|---|---|---|---|
Repository files navigation
ggarchery is intended to extendggplot2's handling of segments with arrowheads. At present it contains one geom and one position adjustment.
First, let's generate some data that would be understood byggplot2's normalgeom_segment():
library(tidyverse)library(ggarchery)tbl <- tibble(x = c(0.1, 0.2), xend = c(0.1, 0.8), y = c(0.1, 0.5), yend = c(0.7, 0.9))The default behaviour ofgeom_arrowsegment() mimics that ofgeom_segment(arrow = arrow())
ggplot(tbl) + geom_segment(aes(x = x, xend = xend, y = y, yend = yend), arrow = arrow()) + xlim(c(0,1)) + ylim(c(0,1))ggplot(tbl) + geom_arrowsegment(aes(x = x, xend = xend, y = y, yend = yend)) + xlim(c(0,1)) + ylim(c(0,1))Thearrows parameter ofgeom_arrowsegment() also behaves exactly like thearrow parameter ofgeom_segment, as a call togrid::arrow():
ggplot(tbl) + geom_arrowsegment(aes(x = x, xend = xend, y = y, yend = yend), arrows = arrow(type = 'closed')) + xlim(c(0,1)) + ylim(c(0,1))Now for the interesting bit. Suppose that we would like the arrowhead to appear at the midpoint of the segment, rather than the end. This can be done by specifyingarrow_positions = 0.5.
ggplot(tbl) + geom_arrowsegment(aes(x = x, xend = xend, y = y, yend = yend), arrow_positions = 0.5) + xlim(c(0,1)) + ylim(c(0,1))Control of the arrow segment works as before:
ggplot(tbl) + geom_arrowsegment(aes(x = x, xend = xend, y = y, yend = yend), arrow_positions = 0.5, arrows = arrow(type = 'closed')) + xlim(c(0,1)) + ylim(c(0,1))Other aesthetics also work as you would hope. There is a subtle difference in the legend as displayed bygeom_segment andgeom_arrowsegment, however:
tbl <- tbl %>% mutate(col = c("A", "B"))ggplot(tbl) + geom_arrowsegment(aes(x = x, xend = xend, y = y, yend = yend, col = col), arrow_positions = 0.5) + xlim(c(0,1)) + ylim(c(0,1))Another key way thatgeom_arrowsegment differs fromgeom_segment is that it has a workingfill aesthetic. This is only visible if the arrowhead is closed. Note that it must be specified asfill even if you want it to simply match thecolour aesthetic, another difference in behaviour fromgeom_segment.
ggplot(tbl) + geom_arrowsegment(aes(x = x, xend = xend, y = y, yend = yend, fill = col), arrow_positions = 0.5, arrows = arrow(type = "closed")) + xlim(c(0,1)) + ylim(c(0,1))ggplot(tbl) + geom_arrowsegment(aes(x = x, xend = xend, y = y, yend = yend, col = col), arrow_positions = 0.5, arrows = arrow(type = "closed")) + xlim(c(0,1)) + ylim(c(0,1))ggplot(tbl) + geom_arrowsegment(aes(x = x, xend = xend, y = y, yend = yend, fill = col, col = col), arrow_positions = 0.5, arrows = arrow(type = "closed")) + xlim(c(0,1)) + ylim(c(0,1))You can also define multiple arrowheads by makingarrow_positions a vector of length greater than 1. All values are expected to fall between 0 and 1, and not be exactly 0:
ggplot(tbl) + geom_arrowsegment(aes(x = x, xend = xend, y = y, yend = yend), arrow_positions = c(0.25, 0.75)) + xlim(c(0,1)) + ylim(c(0,1))If one value is 1, then the final arrowhead appears at the end:
ggplot(tbl) + geom_arrowsegment(aes(x = x, xend = xend, y = y, yend = yend), arrow_positions = c(0.25, 1)) + xlim(c(0,1)) + ylim(c(0,1))The look of each arrow can also be controlled separately by makingarrows a list:
ggplot(tbl) + geom_arrowsegment(aes(x = x, xend = xend, y = y, yend = yend), arrow_positions = c(0.25, 1), arrows = list(arrow(angle = 10), arrow(type = 'closed'))) + xlim(c(0,1)) + ylim(c(0,1))Thearrow_fills option also mimicsarrow.fill ofgeom_segment() but can be a vector. As with a specification offill outside the aesthetics, this takes precedence over afill aesthetic.
ggplot(tbl) + geom_arrowsegment(aes(x = x, xend = xend, y = y, yend = yend), arrow_positions = c(0.25, 1), arrow_fills = c("indianred3", "dodgerblue3"), arrows = arrow(type = "closed")) + xlim(c(0,1)) + ylim(c(0,1))Finally, the geom can be used as an annotation:
ggplot(mtcars) + geom_point(aes(x = disp, y=hp)) + annotate(geom = "arrowsegment", x = 170, y=200, xend = 145, yend = 175, arrow_positions = 0.6, arrows = arrow(type = "closed", length = unit(0.1, "inches")))position_attractsegment() is intended to solve the following problem. Suppose you have nicely laid out a set of labelled points:
pt.tbl <- tibble(x = c(0.25, 0.5, 0.75), y = c(0.25, 0.5, 0.75), labels = c("A", "B", "C"))ggplot(pt.tbl) + geom_point(aes(x,y, fill = labels), size =6, shape = 21) + geom_text(aes(x,y, label = labels)) + xlim(c(0, 1)) + ylim(c(0, 1)) + scale_fill_discrete(guide = "none")If you wish to connect these points usinggeom_segment() with an arrow, the output is a little ugly, as the lines intersect the points:
sg.tbl <- tibble(x = c(0.25, 0.5), y = c(0.25, 0.5), xend = c(0.5, 0.75), yend = c(0.5, 0.75))ggplot(pt.tbl) + geom_point(aes(x,y, fill = labels), size =6, shape = 21) + geom_text(aes(x,y, label = labels)) + geom_segment(data = sg.tbl, aes(x = x, xend = xend, y = y, yend = yend), arrow = arrow()) + xlim(c(0, 1)) + ylim(c(0, 1)) + scale_fill_discrete(guide = "none")position_attractsegment() works by shortening the segment at the start and the end ("attracting" the start and end points towards each other). It can do this in two ways, as determined by thetype_shave option. Iftype_shave = "proportion" (the default), then it takes the proportionsstart_shave andend_shave away:
ggplot(pt.tbl) + geom_point(aes(x,y, fill = labels), size =6, shape = 21) + geom_text(aes(x,y, label = labels)) + geom_segment(data = sg.tbl, aes(x = x, xend = xend, y = y, yend = yend), arrow = arrow(), position = position_attractsegment(start_shave = 0.1, end_shave = 0.1)) + xlim(c(0, 1)) + ylim(c(0, 1)) + scale_fill_discrete(guide = "none")Alternatively, iftype_shave = "distance" then the amount removed is in graph units. This allows for finer control, but has strange effects if the dimensions of the x and y axes are not the same and is only really recommended in combination withcoord_fixed().
ggplot(pt.tbl)+ geom_segment(data = sg.tbl, aes(x = x, xend = xend, y = y, yend = yend), arrow = arrow(), position = position_attractsegment(start_shave = 0, end_shave = 0.05, type_shave = "distance")) + geom_point(aes(x,y, fill = labels), size =6, shape = 21) + geom_text(aes(x,y, label = labels)) + xlim(c(0, 1)) + ylim(c(0, 1)) + scale_fill_discrete(guide = "none") + coord_fixed()(Note here we shaved only the end of the segment, and drew the segment first.)
geom_arrowsegment() andposition_attractsegment() can naturally be used in combination:
ggplot(pt.tbl)+ geom_arrowsegment(data = sg.tbl, aes(x = x, xend = xend, y = y, yend = yend), arrow_positions = c(0.5, 0.6), arrows = arrow(length = unit(0.1, "inches")), position = position_attractsegment(start_shave = 0.05, end_shave = 0.05, type_shave = "distance")) + geom_point(aes(x,y, fill = labels), size =6, shape = 21) + geom_text(aes(x,y, label = labels)) + xlim(c(0, 1)) + ylim(c(0, 1)) + scale_fill_discrete(guide = "none") + coord_fixed()Current these replace onlygeom_segment() and work only for linear coordinate systems. I would like to extend togeom_curve() but the intricacies ofgrid::curveGrob() make that much more complicated. Also the fact that the specified arrow position corresponds to the arrowhead tip can make lines look a little lopsided; it would be much better if the specified point was the midpoint of the arrowhead instead, but this is very difficult usinggrid::arrow() because of the units specification. To do this I would probably need to draw my own arrowheads. Maybe one day...
Next on my to-do list is extending to thegeom_line() andgeom_path() parameterisations.
About
Flexible segment geoms with arrows for ggplot2
Resources
Uh oh!
There was an error while loading.Please reload this page.
Stars
Watchers
Forks
Packages0
Uh oh!
There was an error while loading.Please reload this page.
Contributors2
Uh oh!
There was an error while loading.Please reload this page.


















