【问题标题】:Arrow pointing wrong direction using gganimate使用 gganimate 的箭头指向错误的方向
【发布时间】:2021-01-12 02:34:23
【问题描述】:

我有简单的情节:

sample_data <-
  data.frame(
    x = 1:100
    , y = 1:100
  )

temp_plot <-
  ggplot(sample_data
         , aes(x = x
               , y = y)) +
  geom_line(
    size = 3
    , arrow = arrow()
    , lineend = "round"
    , linejoin = "round"
  ) +
  theme_minimal()

看起来像这样:

我想用gganimate 为它制作动画,如下所示:

temp_animate <-
  temp_plot +
  transition_reveal(x)

anim_save("temp_animate.gif"
          , temp_animate
          , "~/Downloads/"
          , end_pause = 10)

但是,当我这样做时,箭头一直指向错误的方向,直到最后一帧(暂停以表明它在该点是正确的)。

我尝试过使用arrow 中的值(包括各种角度,包括负角),但我所做的一切似乎都无法纠正箭头的方向(它应该指向每一帧中的当前向量)。

如何让箭头始终指向正确的方向? (我在 github 目录中将其作为 an issue 交叉发布)。

【问题讨论】:

  • 我认为您的示例可能缺少一两行代码,因为我看不出 temp_plot 如何在任何地方变成 temp_animate...
  • 谢谢@Z.Lin。我在复制粘贴时错过了这一点。它只是添加transition_reveal(x),现在是问题。

标签: r gganimate


【解决方案1】:

说明

出现这种现象是因为transition_reveal tweens 值来获取每一帧中的过渡位置(箭头所在的位置)。每当计算出的过渡位置与数据集上的实际点重合时,同一位置就会有两组坐标。这会导致反向箭头。

(在您的示例中,箭头一直反转,因为默认帧数与数据中的行数相同,因此每个计算的转换位置都是现有数据点的副本。如果帧number 是其他数字,例如 137,箭头在某些帧中会反转,而在其他帧中会指向直线。)

我们可以用更小的数据集来证明这种现象:

p <- ggplot(data.frame(x = 1:4, y = 1:4),
            aes(x, y)) +
  geom_line(size = 3, arrow = arrow(), lineend = "round", linejoin = "round") +
  theme_minimal() +
  transition_reveal(x)

animate(p + ggtitle("4 frames"), nframes = 4, fps = 1) # arrow remains reversed till the end
animate(p + ggtitle("10 frames"), nframes = 10, fps = 1) # arrow flips back & forth throughout

解决方法

这里的关键函数是来自ggproto对象TransitionRevealexpand_data。我写了一个修改版本,在返回扩展数据集之前添加了对重复位置的检查:

TransitionReveal2 <- ggproto(
  "TransitionReveal2", TransitionReveal,
  expand_panel = function (self, data, type, id, match, ease, enter, exit, params, 
                           layer_index) {    
    row_vars <- self$get_row_vars(data)
    if (is.null(row_vars)) 
      return(data)
    data$group <- paste0(row_vars$before, row_vars$after)
    time <- as.numeric(row_vars$along)
    all_frames <- switch(type,
                         point = tweenr:::tween_along(data, ease, params$nframes, 
                                                      !!time, group, c(1, params$nframes),
                                                      FALSE, params$keep_last),
                         path = tweenr:::tween_along(data, ease, params$nframes, 
                                                     !!time, group, c(1, params$nframes),
                                                     TRUE, params$keep_last),
                         polygon = tweenr:::tween_along(data, ease, params$nframes, 
                                                        !!time, group, c(1, params$nframes),
                                                        TRUE, params$keep_last),
                         stop(type, " layers not currently supported by transition_reveal", 
                              call. = FALSE))
    all_frames$group <- paste0(all_frames$group, "<", all_frames$.frame, ">")
    all_frames$.frame <- NULL
    
    # added step to filter out transition rows with duplicated positions
    all_frames <- all_frames %>%
      filter(!(.phase == "transition" &
                 abs(x - lag(x)) <= sqrt(.Machine$double.eps) &
                 abs(y - lag(y)) <= sqrt(.Machine$double.eps)))
    
    all_frames
  }
)

我们可以定义一个替代版本的transition_reveal 使用上面的代替:

transition_reveal2 <- function (along, range = NULL, keep_last = TRUE) {
  along_quo <- enquo(along)
  gganimate:::require_quo(along_quo, "along")
  ggproto(NULL, TransitionReveal2, # instead of TransitionReveal
          params = list(along_quo = along_quo, range = range, keep_last = keep_last))
}

用原始数据演示:

temp_plot + transition_reveal2(x)

【讨论】:

  • 我仍然不清楚为什么当有重复坐标时箭头是反转的,但知道它就足够了.我将链接到您在我打开的 Github 问题上的答案。也许他们可以在下一次更新中合并您的transition_reveal 版本。谢谢!
  • 箭头反转的原因我也不清楚,但在这一点上这是一个grid 问题而不是gganimate 问题,我真的没有做足够的事情来理解前者. =P
猜你喜欢
  • 2020-04-14
  • 2013-01-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-03
相关资源
最近更新 更多