Стрелка, указывающая неправильное направление с помощью gganimate

#r #gganimate

#r #gganimate

Вопрос:

У меня простой график:

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

Комментарии:

1. Я думаю, что в вашем примере может отсутствовать одна или две строки кода, потому что я не вижу, как temp_plot становится temp_animate где угодно…

2. Спасибо, @Z.Lin. Я пропустил это, когда копировал вставку. Это просто добавление transition_reveal(x) , и теперь это вопрос.

Ответ №1:

Объяснение

Это явление возникает из transition_reveal -за того, что значения tweens для получения позиции перехода (где находится наконечник стрелки) в каждом кадре. Всякий раз, когда вычисленная позиция перехода совпадает с фактической точкой в наборе данных, для одного и того же местоположения будет два набора координат. Это приводит к обратной стрелке.

(В вашем примере стрелка полностью перевернута, потому что количество кадров по умолчанию совпадает с количеством строк в ваших данных, поэтому каждая вычисленная позиция перехода является дубликатом существующей точки данных. Если номер кадра равен какому-либо другому числу, например, 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 amp; forth throughout
  

4 кадра

10 кадров

Обходной путь

Ключевая функция здесь expand_data взята из объекта TransitionReveal ggproto . Я написал модифицированную версию, которая добавляет проверку на наличие дублированных позиций перед возвратом расширенного набора данных:

 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" amp;
                 abs(x - lag(x)) <= sqrt(.Machine$double.eps) amp;
                 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)
  

100 кадров

Комментарии:

1. Мне все еще непонятно, почему стрелка меняется на противоположную, когда есть повторяющиеся координаты, но достаточно знать, что это так . Я дам ссылку на ваш ответ по вопросу Github, который я открыл. Возможно, они смогут включить вашу версию transition_reveal в следующее обновление. Спасибо!

2. Причина разворота стрелки мне тоже не ясна, но на данный момент это grid скорее проблема, чем gganimate проблема, и я действительно недостаточно сделал, чтобы понять первое. = P