如何在ggplot中旋转自定义注释?

时间:2019-02-14 22:44:04

标签: r ggplot2 gganimate

我想旋转ggplot2中annotation_custom中包含的图像。

对于带有gganimate的动画,我想将特定角度的图像添加到折线图中。不幸的是,angle中没有annotation_custom参数。

library(tidyverse)
library(grid)
library(png)

gundf <- tibble(year = c(1999:2017),
                deaths = c(28874, 28663, 29573, 30242, 30136, 29569, 30694, 30896, 
                           31224, 31593, 31347, 31672, 32351, 33563, 33636, 33594, 
                           36252, 38658, 39773))

# Download png from cl.ly/47216db435d3
bullet <- rasterGrob(readPNG("bullet.png"))

gundf %>% 
  ggplot(aes(x=year, y=deaths)) + 
  geom_line(size=1.2) +
  mapply(function(x, y) {
    annotation_custom(bullet, xmin = x-0.5, 
                              xmax = x+0.5, 
                              ymin = y-500, 
                              ymax = y+500)
                         },
    gundf$year, gundf$deaths) + 
  theme_minimal()

结果:

image from cl.ly/b83aefc7a7fa/gunplot.png

从图中可以看出,所有项目符号都是水平对齐的。我想旋转子弹以对应线的斜率。在动画中,这条线应该像射出子弹一样出现(这是另一个问题,因为aes中没有annotate_custom参数)。

提前感谢您的建议!

1 个答案:

答案 0 :(得分:2)

您可以使用magick包旋转png文件:

library(magick)

bullet <- magick::image_read("bullet.png")

## To remove white borders from the example png
bullet <- magick::image_background(bullet, "#FF000000")

## Create angle column
gundf$angle <- seq(0,360, length.out = nrow(gundf))

## Plot
gundf %>% 
  ggplot(aes(x=year, y=deaths)) + 
  geom_line(size=1.2) +
  mapply(function(x, y, angle) {
    annotation_custom(rasterGrob(magick::image_rotate(bullet, angle)),
                              xmin = x-0.5, 
                              xmax = x+0.5, 
                              ymin = y-500, 
                              ymax = y+500)
                         },
    gundf$year, gundf$deaths, gundf$angle) + 
  theme_minimal()

enter image description here

关于您要让项目符号紧随其后的问题,请参见对this answer的评论。使对象具有与ggplot2中的线相同的斜率是棘手的,因为您需要了解绘图区域的长宽比(据我所知,该信息目前未在任何地方打印)。您可以通过使用定义的宽高比将图制作为文件(pdf或png)来解决此问题。然后,您可以使用@Andrie(180/pi * atan(slope * aspect ratio))中的公式,而不是我在示例中使用的公式。可能会有轻微的不匹配,您可以尝试使用常数来进行调整。另外,在数据集中的每个点之间线性插值一个点可能是一个好主意,因为现在您正在绘制坡度变化的项目符号。在动画中执行此操作效果不佳。在坡度恒定的地方绘制子弹可能会更容易。