多个 gganimate 图既堆叠又并排
Multiple gganimate plots both stacked and side by side
我有四个帧数相同的动画情节,我想要其中三个堆叠的动画和三个堆叠动画右侧的第四个。通常我会使用 grid.arrange 之类的东西,但这似乎不适用于 gganimate。
我根据此处的代码得到了以下代码:https://github.com/thomasp85/gganimate/wiki/Animation-Composition
a_mgif <- image_read(a_gif)
b_mgif <- image_read(b_gif)
c_mgif <- image_read(c_gif)
d_mgif <- image_read(d_gif)
new_gif <- image_append(c(a_mgif[1], b_mgif[1], c_mgif[1], d_mgif[1]), stack = TRUE)
for(i in 2:100){
combined <- image_append(c(a_mgif[i], b_mgif[i], c_mgif[i], d_mgif[i]), stack = TRUE)
new_gif <- c(new_gif, combined)
}
magick::image_write(new_gif, path="animation.1.gif")
这工作正常并生成四个堆叠的动画图。我试图修改它,使第四个图位于前三个堆叠图的右侧,如下所示:
new_gif.1 <- image_append(c(a_mgif[1], b_mgif[1], c_mgif[1]), stack = TRUE)
new_gif.2 <- image_append(c(new_gif.1, d_mgif[1]), stack = FALSE)
for(i in 2:100){
combined.1 <- image_append(c(a_mgif[i], b_mgif[i], c_mgif[i]), stack = TRUE)
combined.2 <- image_append(c(combined.1, d_mgif[i]), stack = FALSE)
new_gif.2 <- c(new_gif.2,combined.2)
}
magick::image_write(new_gif.2, path="animation.2.gif")
这似乎可行,直到写入文件为止。写这个文件需要很长时间,我让它 运行 几个小时,但它仍然没有完成,而第一个将它们全部堆叠起来的版本是在一分钟内写完的,所以很明显出了问题。这两个示例中的 data/plots 完全相同。关于这里出了什么问题有什么想法吗?
对我有用的是将 image_append
调用包装到 image_flatten
中。我也是先把img1和img4水平合并,再把img2和img3叠起来。
这里我只回收了示例中的两个动画,但这个解决方案应该也适用于四个独立的动画 - 至少对我来说,在 R4.0 上使用 ImageMagick 6.9.10.23 和 magick_2.3,虽然这需要大约 3 分钟,可能需要 630 MB 的临时存储空间:
library(dplyr)
library(ggplot2)
library(magick)
library(gganimate)
A <- rnorm(100,50,10)
B <- rnorm(100,50,10)
DV <- c(A,B)
IV <- rep(c("A","B"), each=100)
sims <- rep(rep(1:10, each=10), 2)
df <- data.frame(sims, IV, DV)
means_df <- df %>%
group_by(sims,IV) %>%
summarize(means=mean(DV),
sem = sd(DV)/sqrt(length(DV)))
stats_df <- df %>%
group_by(sims) %>%
summarize(ts = t.test(DV~IV,var.equal=TRUE)$statistic)
a <- ggplot(means_df, aes(x = IV,y = means, fill = IV)) +
geom_bar(stat = "identity") +
geom_point(aes(x = IV, y = DV), data = df, alpha = .25) +
geom_errorbar(aes(ymin = means - sem, ymax = means + sem), width = .2) +
theme_classic() +
transition_states(
states = sims,
transition_length = 2,
state_length = 1
) +
enter_fade() +
exit_shrink() +
ease_aes('sine-in-out')
a_gif <- animate(a, width = 240, height = 240, renderer = magick_renderer())
b <- ggplot(stats_df, aes(x = ts))+
geom_vline(aes(xintercept = ts, frame = sims))+
geom_line(aes(x=x,y=y),
data = data.frame(x = seq(-5,5, .1),
y = dt(seq(-5,5, .1), df = 18))) +
theme_classic() +
ylab("density") +
xlab("t value") +
transition_states(
states = sims,
transition_length = 2,
state_length = 1
) +
enter_fade() +
exit_shrink() +
ease_aes('sine-in-out')
b_gif <- animate(b, width = 240, height = 240, renderer = magick_renderer())
c_gif <- animate(b, width = 240, height = 240, renderer = magick_renderer())
d_gif <- animate(a, width = 240, height = 240, renderer = magick_renderer())
i=1
combined <- image_append(c(a_gif[i], d_gif[i]))
new_gif <- image_append(c(image_flatten(combined),
b_gif[i], c_gif[i]), stack=TRUE)
for(i in 2:100){
combined <- image_append(c(a_gif[i], d_gif[i]))
fullcombined <- image_append(c(image_flatten(combined),
b_gif[i], c_gif[i]), stack=TRUE)
new_gif <- c(new_gif, fullcombined)
}
image_write(new_gif, format="gif", path="animation.2.gif")
编辑:替代
或者,您可以使用 cowplot
排列绘图并循环生成各个帧,然后使用 gifski
制作动画;这在图像放置方面更加灵活,因为您可以将坐标添加到 draw_image
(参见相应的 cowplot
示例)。下面是一个简单的网格示例:
library(dplyr)
library(ggplot2)
library(magick)
library(gganimate)
library(cowplot)
library(gifski)
A <- rnorm(100,50,10)
B <- rnorm(100,50,10)
DV <- c(A,B)
IV <- rep(c("A","B"), each=100)
sims <- rep(rep(1:10, each=10), 2)
df <- data.frame(sims, IV, DV)
means_df <- df %>%
group_by(sims,IV) %>%
summarize(means=mean(DV),
sem = sd(DV)/sqrt(length(DV)))
stats_df <- df %>%
group_by(sims) %>%
summarize(ts = t.test(DV~IV,var.equal=TRUE)$statistic)
a <- ggplot(means_df, aes(x = IV,y = means, fill = IV)) +
geom_bar(stat = "identity") +
geom_point(aes(x = IV, y = DV), data = df, alpha = .25) +
geom_errorbar(aes(ymin = means - sem, ymax = means + sem), width = .2) +
theme_classic() +
transition_states(
states = sims,
transition_length = 2,
state_length = 1
) +
enter_fade() +
exit_shrink() +
ease_aes('sine-in-out')
a_gif <- animate(a, width = 240, height = 240, renderer = magick_renderer())
b <- ggplot(stats_df, aes(x = ts))+
geom_vline(aes(xintercept = ts, frame = sims))+
geom_line(aes(x=x,y=y),
data = data.frame(x = seq(-5,5, .1),
y = dt(seq(-5,5, .1), df = 18))) +
theme_classic() +
ylab("density") +
xlab("t value") +
transition_states(
states = sims,
transition_length = 2,
state_length = 1
) +
enter_fade() +
exit_shrink() +
ease_aes('sine-in-out')
b_gif <- animate(b, width = 240, height = 240, renderer = magick_renderer())
c_gif <- animate(b, width = 240, height = 240, renderer = magick_renderer())
d_gif <- animate(a, width = 240, height = 240, renderer = magick_renderer())
tdir <- tempdir()
for(i in 1:100){
new_gif <- plot_grid(ggdraw() + draw_image(a_gif[i], scale = 0.9),
ggdraw() + draw_image(d_gif[i], scale = 0.9),
ggdraw() + draw_image(b_gif[i], scale = 0.9),
ggdraw(),
ggdraw() + draw_image(c_gif[i], scale = 0.9),
ncol=2)
ggsave(
filename = file.path(tdir, paste0("out_", sprintf("%03d", i), ".png")),
plot = new_gif, width = 2.4, height = 3.6, device = "png")
}
png_files <- sort(list.files(path = tdir, pattern = "out_", full.names = TRUE))
gifski(png_files, gif_file = "out.gif", width = 480, height = 720, delay = .1,
progress = TRUE)
编辑 #2(2021 年 5 月):
自从我最初的回答以来发生了一些变化,正如@agbarnett 所指出的,渲染器现在必须在所有 animate
命令中明确设置为 renderer = magick_renderer()
。
我有四个帧数相同的动画情节,我想要其中三个堆叠的动画和三个堆叠动画右侧的第四个。通常我会使用 grid.arrange 之类的东西,但这似乎不适用于 gganimate。
我根据此处的代码得到了以下代码:https://github.com/thomasp85/gganimate/wiki/Animation-Composition
a_mgif <- image_read(a_gif)
b_mgif <- image_read(b_gif)
c_mgif <- image_read(c_gif)
d_mgif <- image_read(d_gif)
new_gif <- image_append(c(a_mgif[1], b_mgif[1], c_mgif[1], d_mgif[1]), stack = TRUE)
for(i in 2:100){
combined <- image_append(c(a_mgif[i], b_mgif[i], c_mgif[i], d_mgif[i]), stack = TRUE)
new_gif <- c(new_gif, combined)
}
magick::image_write(new_gif, path="animation.1.gif")
这工作正常并生成四个堆叠的动画图。我试图修改它,使第四个图位于前三个堆叠图的右侧,如下所示:
new_gif.1 <- image_append(c(a_mgif[1], b_mgif[1], c_mgif[1]), stack = TRUE)
new_gif.2 <- image_append(c(new_gif.1, d_mgif[1]), stack = FALSE)
for(i in 2:100){
combined.1 <- image_append(c(a_mgif[i], b_mgif[i], c_mgif[i]), stack = TRUE)
combined.2 <- image_append(c(combined.1, d_mgif[i]), stack = FALSE)
new_gif.2 <- c(new_gif.2,combined.2)
}
magick::image_write(new_gif.2, path="animation.2.gif")
这似乎可行,直到写入文件为止。写这个文件需要很长时间,我让它 运行 几个小时,但它仍然没有完成,而第一个将它们全部堆叠起来的版本是在一分钟内写完的,所以很明显出了问题。这两个示例中的 data/plots 完全相同。关于这里出了什么问题有什么想法吗?
对我有用的是将 image_append
调用包装到 image_flatten
中。我也是先把img1和img4水平合并,再把img2和img3叠起来。
这里我只回收了示例中的两个动画,但这个解决方案应该也适用于四个独立的动画 - 至少对我来说,在 R4.0 上使用 ImageMagick 6.9.10.23 和 magick_2.3,虽然这需要大约 3 分钟,可能需要 630 MB 的临时存储空间:
library(dplyr)
library(ggplot2)
library(magick)
library(gganimate)
A <- rnorm(100,50,10)
B <- rnorm(100,50,10)
DV <- c(A,B)
IV <- rep(c("A","B"), each=100)
sims <- rep(rep(1:10, each=10), 2)
df <- data.frame(sims, IV, DV)
means_df <- df %>%
group_by(sims,IV) %>%
summarize(means=mean(DV),
sem = sd(DV)/sqrt(length(DV)))
stats_df <- df %>%
group_by(sims) %>%
summarize(ts = t.test(DV~IV,var.equal=TRUE)$statistic)
a <- ggplot(means_df, aes(x = IV,y = means, fill = IV)) +
geom_bar(stat = "identity") +
geom_point(aes(x = IV, y = DV), data = df, alpha = .25) +
geom_errorbar(aes(ymin = means - sem, ymax = means + sem), width = .2) +
theme_classic() +
transition_states(
states = sims,
transition_length = 2,
state_length = 1
) +
enter_fade() +
exit_shrink() +
ease_aes('sine-in-out')
a_gif <- animate(a, width = 240, height = 240, renderer = magick_renderer())
b <- ggplot(stats_df, aes(x = ts))+
geom_vline(aes(xintercept = ts, frame = sims))+
geom_line(aes(x=x,y=y),
data = data.frame(x = seq(-5,5, .1),
y = dt(seq(-5,5, .1), df = 18))) +
theme_classic() +
ylab("density") +
xlab("t value") +
transition_states(
states = sims,
transition_length = 2,
state_length = 1
) +
enter_fade() +
exit_shrink() +
ease_aes('sine-in-out')
b_gif <- animate(b, width = 240, height = 240, renderer = magick_renderer())
c_gif <- animate(b, width = 240, height = 240, renderer = magick_renderer())
d_gif <- animate(a, width = 240, height = 240, renderer = magick_renderer())
i=1
combined <- image_append(c(a_gif[i], d_gif[i]))
new_gif <- image_append(c(image_flatten(combined),
b_gif[i], c_gif[i]), stack=TRUE)
for(i in 2:100){
combined <- image_append(c(a_gif[i], d_gif[i]))
fullcombined <- image_append(c(image_flatten(combined),
b_gif[i], c_gif[i]), stack=TRUE)
new_gif <- c(new_gif, fullcombined)
}
image_write(new_gif, format="gif", path="animation.2.gif")
编辑:替代
或者,您可以使用 cowplot
排列绘图并循环生成各个帧,然后使用 gifski
制作动画;这在图像放置方面更加灵活,因为您可以将坐标添加到 draw_image
(参见相应的 cowplot
示例)。下面是一个简单的网格示例:
library(dplyr)
library(ggplot2)
library(magick)
library(gganimate)
library(cowplot)
library(gifski)
A <- rnorm(100,50,10)
B <- rnorm(100,50,10)
DV <- c(A,B)
IV <- rep(c("A","B"), each=100)
sims <- rep(rep(1:10, each=10), 2)
df <- data.frame(sims, IV, DV)
means_df <- df %>%
group_by(sims,IV) %>%
summarize(means=mean(DV),
sem = sd(DV)/sqrt(length(DV)))
stats_df <- df %>%
group_by(sims) %>%
summarize(ts = t.test(DV~IV,var.equal=TRUE)$statistic)
a <- ggplot(means_df, aes(x = IV,y = means, fill = IV)) +
geom_bar(stat = "identity") +
geom_point(aes(x = IV, y = DV), data = df, alpha = .25) +
geom_errorbar(aes(ymin = means - sem, ymax = means + sem), width = .2) +
theme_classic() +
transition_states(
states = sims,
transition_length = 2,
state_length = 1
) +
enter_fade() +
exit_shrink() +
ease_aes('sine-in-out')
a_gif <- animate(a, width = 240, height = 240, renderer = magick_renderer())
b <- ggplot(stats_df, aes(x = ts))+
geom_vline(aes(xintercept = ts, frame = sims))+
geom_line(aes(x=x,y=y),
data = data.frame(x = seq(-5,5, .1),
y = dt(seq(-5,5, .1), df = 18))) +
theme_classic() +
ylab("density") +
xlab("t value") +
transition_states(
states = sims,
transition_length = 2,
state_length = 1
) +
enter_fade() +
exit_shrink() +
ease_aes('sine-in-out')
b_gif <- animate(b, width = 240, height = 240, renderer = magick_renderer())
c_gif <- animate(b, width = 240, height = 240, renderer = magick_renderer())
d_gif <- animate(a, width = 240, height = 240, renderer = magick_renderer())
tdir <- tempdir()
for(i in 1:100){
new_gif <- plot_grid(ggdraw() + draw_image(a_gif[i], scale = 0.9),
ggdraw() + draw_image(d_gif[i], scale = 0.9),
ggdraw() + draw_image(b_gif[i], scale = 0.9),
ggdraw(),
ggdraw() + draw_image(c_gif[i], scale = 0.9),
ncol=2)
ggsave(
filename = file.path(tdir, paste0("out_", sprintf("%03d", i), ".png")),
plot = new_gif, width = 2.4, height = 3.6, device = "png")
}
png_files <- sort(list.files(path = tdir, pattern = "out_", full.names = TRUE))
gifski(png_files, gif_file = "out.gif", width = 480, height = 720, delay = .1,
progress = TRUE)
编辑 #2(2021 年 5 月):
自从我最初的回答以来发生了一些变化,正如@agbarnett 所指出的,渲染器现在必须在所有 animate
命令中明确设置为 renderer = magick_renderer()
。