Proportionally sized arrows in ggplot

2019-06-28 00:59发布

Building on ggplot2's seals example, I'm trying to change the thickness of arrows so their overall size better reflects the data variable. I can specify length and thickness, but don't know how to change the size of the arrow-head. Very grateful for any suggestions.

require(ggplot2)
require(grid)

d = seals[sample(1:nrow(seals), 100),]
d$size = sqrt(sqrt(d$delta_long^2 + d$delta_lat^2))

ggplot(d, aes(x = long, y = lat, size = size)) +
  geom_segment(aes(xend = long + delta_long, yend = lat + delta_lat), arrow = arrow(length = unit(0.1,"cm")))

enter image description here


Edit

Solution code:

ggplot(d, aes(x = long, y = lat, size = size)) +
  geom_segment(aes(xend = long + delta_long, yend = lat + delta_lat), 
               arrow = arrow(length = unit(d$size/3, "cm"), type='closed')) +
  scale_size(range = c(0, 2))

标签: r ggplot2
1条回答
看我几分像从前
2楼-- · 2019-06-28 01:50

I can't say this is a complete solution to your problem, but at least it can be a start.

ggplot(d, aes(x = long, y = lat, size = size)) +
  geom_segment(aes(xend = long + delta_long, yend = lat + delta_lat), 
              arrow = arrow(length = unit(0.7, "cm"))) + 
  scale_size(range = c(1, 2))

My changes are minimal: bigger arrow heads and size scale. The upper limit on size scale is the most important if you aim to avoid overplotting.

enter image description here

From now on, it's probably a good idea to leave only the arrow heads, since the lines are not visible when the size is small. Here's a dirty hack for that:

 ggplot(d, aes(x = long, y = lat, size = size)) +
   geom_segment(aes(xend = long + delta_long/100, yend = lat + delta_lat/100), 
               arrow = arrow(length = unit(0.7,"cm"))) + 
   scale_size(range = c(1, 2))

enter image description here

Of course, it is crucial to keep an appropriate visual relation between big and small values! Otherwise, your plot may become misleading. But that depends on the data, so I cannot give you further advice. Sorry if that's an obvious point.

UPD: turns out, unit() function is vectorized, so it comes to the rescue!

ggplot(d, aes(x = long, y = lat, size = size)) +
  geom_segment(aes(xend = long + delta_long/100, yend = lat + delta_lat/100), 
              arrow = arrow(length = unit(d$size * 5,"cm"))) + 
  scale_size(range = c(1, 2))

enter image description here

查看更多
登录 后发表回答