gganimate 不显示所有帧

gganimate not showing all frames

我想用 138 状态 制作一个简单的 gif。我不需要在每个状态之间进行任何花哨的转换,但我确实需要每个状态都出现在我的 gif 中。目前,gganimate 正在缩短我的 gif,不显示最后 ~30ish 状态。

例子

df <- lapply(1:138, function(t){
  data.frame(
    DT = as.POSIXct("2019-01-01 12:00:00", tz = "UTC") + t*24*60*60,
    x = seq(-3, 3, length.out = 100),
    y = t * seq(-3, 3, length.out = 100)
  )
})
df <- do.call(rbind, df)
range(df$DT)  # "2019-01-02 12:00:00 UTC" "2019-05-19 12:00:00 UTC"

p <- ggplot(data = df, mapping = aes(x = x, y = y)) + 
  geom_point()+ 
  transition_states(states = DT, transition_length = 0, state_length = 1)+
  labs(title = 'ScrapeDT: {previous_state}')
p

如您所见,gif 一直播放到 2019-04-10 左右,而不是 2019-05-19。我也试过修改 animate() 但没有成功。例如,

animate(
  plot = p, 
  nframes = length(unique(df$DT)), 
  fps = 8, 
  end_pause = 8
)

我怎样才能使这项工作使 每个 所需的状态显示 0.25 秒?

看来你被帧采样搞砸了。来自 ?animate:

The length and framerate is decided on render time and can be any two combination of nframes, fps, and duration.

Rendering is happening in discrete time units. This means that any event in the animation is rounded of to the nearest frame (e.g. entering will always take a whole number of frames). This means that rounding artifacts are possible when only rendering few frames.

To avoid this you can increase the detail argument. detail will get multiplied to nframes and the resulting number of frames will get calculated, but only nframes evenly spaced frames are rendered.

确保打印每个状态的简单解决方案是设置 detail > 1。通常 detail = fps 将保证使用每一帧。

animate(
  plot = p, 
  nframes = length(unique(df$DT)), 
  detail = 8,
  fps = 8, 
  end_pause = 8
)

docs 中所述,transition_manual() 正是您所需要的:

This transition allows you to map a variable in your data to a specific frame in the animation. No tweening of data will be made and the number of frames in the animation will be decided by the number of levels in the frame variable.

注意下面我用 transition_manual()labs() 做了什么。

library(tidyverse)
library(gganimate)

df <- lapply(1:138, function(t){
  data.frame(
    DT = as.POSIXct("2019-01-01 12:00:00", tz = "UTC") + t * 24 * 60 * 60,
    x = seq(-3, 3, length.out = 100),
    y = t * seq(-3, 3, length.out = 100)
  )
})
df <- do.call(rbind, df)

p <- ggplot(data = df, mapping = aes(x = x, y = y)) + 
  geom_point()+ 
  transition_manual(frames = DT)+
  labs(title = 'ScrapeDT: {current_frame}')

animate(
  plot = p, 
  nframes = length(unique(df$DT)), 
  fps = 4, 
  end_pause = 8
)