gpt4 book ai didi

r - gganimate 和(有时)空方面的问题

转载 作者:行者123 更新时间:2023-12-02 14:52:10 25 4
gpt4 key购买 nike

我正在观察 gganimate 中的一些我无法解释的行为,我想了解我做错了什么(或者它是否是一个错误)。

例如,这是一个非常简单的数据集及其绘图:

library(dplyr) # dplyr_0.7.8
library(tidyr) # tidyr_0.8.2

crossing(p = 1:2,
t = seq(0, 1, len = 30),
s = c(0, .5)) %>%
mutate(x = t,
y = t^p) %>%
filter(t > s) ->
Z

library(ggplot2) # ggplot2_3.1.0

Z %>%
ggplot(aes(x,y)) +
facet_wrap(~s) +
geom_point()

正如预期的那样,第二个面 (s=0.5) 只有 x > 0.5 的数据,这(根据 tibble Z 的构造方式)来自 t > 0.5。

如果要对上述数据进行动画处理(使用 t 作为时间),我希望第二个方面在动画的前半部分是空的,然后显示与第一个方面相同的内容下半场。然而:

library(gganimate) # gganimate_1.0.2
Z %>%
ggplot(aes(x, y, group = interaction(p,s))) +
facet_wrap(~s) +
geom_point() +
transition_time(t) +
ggtitle('{frame_time}')

上面的代码生成了一个动画(使用gifski_0.8.6),它有两个面,其中第二个面只简单地显示它的点,而且在错误的时间显示它们(即在开始的时候)动画)。

我是不是遗漏了什么,或者这是一个错误?

最佳答案

这将是一个相当长的答案,分为 3 个部分。您可以从这里开始查看解释,或向下滚动以查看两个建议的解决方法。

说明

这似乎是 transition_time 的问题, 当它以一个空的 facet 开始时表现得很奇怪。

通过底层代码调试后,我认为问题出在 expand_panel 上。 TransitionTime下的功能.我们可以通过运行 debug(environment(TransitionTime$expand_panel)) 来证明这一点在绘制有问题的动画之前。查看以下调试代码中 A-B 行之前和之后发生的情况:

> TransitionTime$expand_panel
<ggproto method>
<Wrapper function>
function (...)
f(..., self = self)

<Inner function (f)>
function (self, data, type, id, match, ease, enter, exit, params,
layer_index)
{
... # omitted

true_frame <- seq(times[1], times[length(times)])

# line A
all_frames <- all_frames[
all_frames$.frame %in% which(true_frame > 0 & true_frame <= params$nframes),
,
drop = FALSE]

# line B
all_frames$.frame <- all_frames$.frame - min(all_frames$.frame) + 1

... # omitted
}

在每个方面面板中,all_frames是一个数据框,其中包含与该特定方面对应的原始数据行,以及在它们之间传输的其他行。 true_frame是数据应显示的有效帧的整数向量。

对于第一个面板(即 s = 0),这是 A 行之前的内容:

> true_frame
[1] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
[23] 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
[45] 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
[67] 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
[89] 89 90 91 92 93 94 95 96 97 98 99 100

> head(all_frames)
x y group PANEL shape colour size fill alpha stroke .id .phase .frame
1 0.03448276 0.034482759 1 1 19 black 1.5 NA NA 0.5 1 raw 1
45 0.03448276 0.001189061 2 1 19 black 1.5 NA NA 0.5 2 raw 1
3 0.04310345 0.043103448 1 1 19 #000000FF 1.5 NA NA 0.5 1 transition 2
4 0.04310345 0.002080856 2 1 19 #000000FF 1.5 NA NA 0.5 2 transition 2
5 0.05172414 0.051724138 1 1 19 #000000FF 1.5 NA NA 0.5 1 transition 3
6 0.05172414 0.002972652 2 1 19 #000000FF 1.5 NA NA 0.5 2 transition 3

> tail(all_frames)
x y group PANEL shape colour size fill alpha stroke .id .phase .frame
530 0.9827586 0.9827586 1 1 19 #000000FF 1.5 NA NA 0.5 1 transition 98
629 0.9827586 0.9661118 2 1 19 #000000FF 1.5 NA NA 0.5 2 transition 98
716 0.9913793 0.9913793 1 1 19 #000000FF 1.5 NA NA 0.5 1 transition 99
816 0.9913793 0.9830559 2 1 19 #000000FF 1.5 NA NA 0.5 2 transition 99
434 1.0000000 1.0000000 1 1 19 black 1.5 NA NA 0.5 1 raw 100
871 1.0000000 1.0000000 2 1 19 black 1.5 NA NA 0.5 2 raw 100

all_frames在 A-B 行之后没有变化,所以我不会再重复控制台打印输出。

另一方面,对于第二个面板(即 s = 0.5),线 A-B 产生了显着差异。这是 A 行之前的内容:

> true_frame
[1] 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
[25] 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
[49] 98 99 100

> head(all_frames)
x y group PANEL shape colour size fill alpha stroke .id .phase .frame
16 0.5172414 0.5172414 3 2 19 black 1.5 NA NA 0.5 NA raw 49
60 0.5172414 0.2675386 4 2 19 black 1.5 NA NA 0.5 NA raw 49
3 0.5241379 0.5241379 3 2 19 #000000FF 1.5 NA NA 0.5 3 transition 50
4 0.5241379 0.2749108 4 2 19 #000000FF 1.5 NA NA 0.5 4 transition 50
5 0.5310345 0.5310345 3 2 19 #000000FF 1.5 NA NA 0.5 3 transition 51
6 0.5310345 0.2822830 4 2 19 #000000FF 1.5 NA NA 0.5 4 transition 51

> tail(all_frames)
x y group PANEL shape colour size fill alpha stroke .id .phase .frame
513 0.9827586 0.9827586 3 2 19 #000000FF 1.5 NA NA 0.5 3 transition 98
617 0.9827586 0.9661118 4 2 19 #000000FF 1.5 NA NA 0.5 4 transition 98
710 0.9913793 0.9913793 3 2 19 #000000FF 1.5 NA NA 0.5 3 transition 99
87 0.9913793 0.9830559 4 2 19 #000000FF 1.5 NA NA 0.5 4 transition 99
441 1.0000000 1.0000000 3 2 19 black 1.5 NA NA 0.5 3 raw 100
88 1.0000000 1.0000000 4 2 19 black 1.5 NA NA 0.5 4 raw 100

true_frames涵盖范围 50-100,而帧数在 all_frames从 49 开始。很好,足够接近,我们可以为匹配 true_frames 中的帧的数据帧子集。 & 删除带有 .frame < 50 的行,但这不是行 A 中发生的情况。观察:

> true_frame > 0 & true_frame <= params$nframes # all TRUE
[1] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[20] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[39] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE

> which(true_frame > 0 & true_frame <= params$nframes)
# values start from 1, rather than 1st frame number
[1] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
[33] 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51

> all_frames$.frame %in% which(true_frame > 0 & true_frame <= params$nframes)
# only the first few frames match the last few values!
[1] TRUE TRUE TRUE TRUE TRUE TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[16] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[31] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[46] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[61] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[76] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[91] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE

> all_frames
# consequently, only the first few frames are left after the subsetting
x y group PANEL shape colour size fill alpha stroke .id .phase .frame
16 0.5172414 0.5172414 3 2 19 black 1.5 NA NA 0.5 NA raw 49
60 0.5172414 0.2675386 4 2 19 black 1.5 NA NA 0.5 NA raw 49
3 0.5241379 0.5241379 3 2 19 #000000FF 1.5 NA NA 0.5 3 transition 50
4 0.5241379 0.2749108 4 2 19 #000000FF 1.5 NA NA 0.5 4 transition 50
5 0.5310345 0.5310345 3 2 19 #000000FF 1.5 NA NA 0.5 3 transition 51
6 0.5310345 0.2822830 4 2 19 #000000FF 1.5 NA NA 0.5 4 transition 51

我们现在来到 B 行 ( all_frames$.frame <- all_frames$.frame - min(all_frames$.frame) + 1 ),它基本上将帧重新居中以从 1 开始。因此,这就是我们在 B 行之后得到的:

> all_frames
x y group PANEL shape colour size fill alpha stroke .id .phase .frame
16 0.5172414 0.5172414 3 2 19 black 1.5 NA NA 0.5 NA raw 1
60 0.5172414 0.2675386 4 2 19 black 1.5 NA NA 0.5 NA raw 1
3 0.5241379 0.5241379 3 2 19 #000000FF 1.5 NA NA 0.5 3 transition 2
4 0.5241379 0.2749108 4 2 19 #000000FF 1.5 NA NA 0.5 4 transition 2
5 0.5310345 0.5310345 3 2 19 #000000FF 1.5 NA NA 0.5 3 transition 3
6 0.5310345 0.2822830 4 2 19 #000000FF 1.5 NA NA 0.5 4 transition 3

好了:由于 expand_panel 中的 A-B 行,我们得到了问题中描述的现象:第二个面板中的动画从第 1 帧开始,& 只持续了可怜的 3 帧就一起消失了。

解决方法 1

因为我们知道是什么导致了问题,我们可以调整 expand_panel 的代码, 并定义一个稍微不同的版本 transition_time而是使用它:

library(tweenr)

TransitionTime2 <- ggproto(
"TransitionTime2",
TransitionTime,
expand_panel = function (self, data, type, id, match, ease, enter, exit, params,
layer_index) {
row_time <- self$get_row_vars(data)
if (is.null(row_time))
return(data)
data$group <- paste0(row_time$before, row_time$after)
time <- as.integer(row_time$time)
states <- split(data, time)
times <- as.integer(names(states))
nframes <- diff(times)
nframes[1] <- nframes[1] + 1
if (times[1] <= 1) {
all_frames <- states[[1]]
states <- states[-1]
}
else {
all_frames <- data[0, , drop = FALSE]
nframes <- c(times[1] - 1, nframes)
}
if (times[length(times)] < params$nframes) {
states <- c(states, list(data[0, , drop = FALSE]))
nframes <- c(nframes, params$nframes - times[length(times)])
}
for (i in seq_along(states)) {
all_frames <- switch(type, point = tween_state(all_frames,
states[[i]], ease, nframes[i],
!!id, enter, exit),
path = transform_path(all_frames,
states[[i]], ease, nframes[i],
!!id, enter, exit, match),
polygon = transform_polygon(all_frames,
states[[i]], ease, nframes[i],
!!id, enter, exit, match),
sf = transform_sf(all_frames,
states[[i]], ease, nframes[i],
!!id, enter, exit),
stop(type,
" layers not currently supported by transition_time",
call. = FALSE))
}
true_frame <- seq(times[1], times[length(times)])
all_frames <- all_frames[
all_frames$.frame %in%
# which(true_frame > 0 & true_frame <= params$nframes),
true_frame[which(true_frame > 0 & true_frame <= params$nframes)], # tweak line A
,
drop = FALSE]
# all_frames$.frame <- all_frames$.frame - min(all_frames$.frame) + 1 # remove line B
all_frames$group <- paste0(all_frames$group, "<", all_frames$.frame, ">")
all_frames$.frame <- NULL
all_frames
})

transition_time2 <- function (time, range = NULL) {
time_quo <- enquo(time)
gganimate:::require_quo(time_quo, "time")
ggproto(NULL, TransitionTime2,
params = list(time_quo = time_quo, range = range))
}

结果:

Z %>%
ggplot(aes(x, y, group = interaction(p,s))) +
geom_point() +
facet_wrap(~s) +
transition_time2(t) +
ggtitle('{frame_time}')

workaround 1

解决方法 2

定义全新的 ggproto 对象可能有点矫枉过正,坦率地说,我对 gganimate 包的了解还不够,无法确定这样做不会破坏其他任何东西。

作为一种破坏性较小的替代方案,我们可以简单地预处理数据框以包含每个方面的相同时间值范围(以及任何其他感兴趣的分组变量),并使新行不可见:

Z %>% 
mutate(alpha = 1) %>%
tidyr::complete(t, s, p, fill = list(alpha = 0)) %>%
group_by(s, p) %>%
arrange(t) %>%
tidyr::fill(x, y, .direction = "up") %>%
ungroup() %>%

ggplot(aes(x, y, group = interaction(p, s), alpha = alpha)) +
geom_point() +
facet_wrap(~ s) +
scale_alpha_identity() +
transition_time(t) +
ggtitle('{frame_time}')

workaround 2

关于r - gganimate 和(有时)空方面的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55110492/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com