Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Flexible segment geoms with arrows for ggplot2

NotificationsYou must be signed in to change notification settings

mdhall272/ggarchery

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ggarchery is intended to extendggplot2's handling of segments with arrowheads. At present it contains one geom and one position adjustment.

geom_arrowsegment() allows placement of one or more arrowheads at any point on a segment

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() allows you to automatically shave the ends of arrow segments

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()

Limitations

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

Stars

Watchers

Forks

Packages

No packages published

Contributors2

  •  
  •  

Languages


[8]ページ先頭

©2009-2025 Movatter.jp