如何用gganimate实现geom_density_2d_filled的累积时间动画?
实现geom_density_2d_filled的累积动画
要将2D密度动画改为累积模式(每一帧基于当前及之前所有时间点的数据计算密度),最可靠的方式是先预处理生成累积数据集,再配合gganimate渲染动画。以下是具体实现方案:
方法一:预处理生成累积数据集
通过purrr::accumulate生成每个时间点对应的累积数据子集,确保每个帧使用的是从起始到当前月份的所有点:
library(dplyr) library(sf) library(geofi) library(ggplot2) library(gganimate) library(purrr) # 加载芬兰 municipality 数据 muns <- geofi::get_municipalities(year = 2022) # 生成样本点数据 points <- sf::st_sample(muns, 240) %>% as.data.frame() points[c("x", "y")] <- sf::st_coordinates(points$geometry) monthly <- seq(as.Date("2020/1/1"), by = "month", length.out = 24) %>% rep(., each = 10) points$monthly <- monthly # 生成累积数据集:每个帧对应到该月份及之前的所有点 cumulative_points <- points %>% arrange(monthly) %>% split(.$monthly) %>% # 按月份拆分数据 accumulate(~bind_rows(.x, .y)) %>% # 累积合并子集 bind_rows(.id = "frame_month") %>% mutate(frame_month = as.Date(frame_month)) # 转换为日期格式 # 绘制累积动画 p <- ggplot() + # 使用累积数据计算密度,group参数确保每个帧独立计算 geom_density_2d_filled(data = cumulative_points, aes(x = x, y = y, alpha = after_stat(level), group = frame_month)) + geom_sf(data = muns, fill = NA, color = "black") + coord_sf(default_crs = sf::st_crs(3067)) + geom_point(data = cumulative_points, aes(x = x, y = y), alpha = 0.1) + scale_alpha_manual(values = c(0, rep(0.75, 13)), guide = "none") + # 按累积帧切换 transition_states(frame_month, transition_length = 1, state_length = 40) + labs(title = "Month: {closest_state}") + ease_aes("linear") # 渲染并保存动画 animate(p, renderer = gganimate::gifski_renderer()) gganimate::anim_save(filename = "cumulative_so.gif", path = "anim")
原理说明
- 预处理阶段:
accumulate函数会依次将每个月份的子集与之前所有子集合并,生成24个累积数据集(对应24个月份),每个数据集标记对应的frame_month。 - 绘图阶段:
group = frame_month确保geom_density_2d_filled为每个帧单独计算基于累积数据的密度分布,而非复用之前的计算结果。
替代思路:动态数据过滤
如果不想生成完整的累积数据集,也可以在ggplot中使用动态过滤配合transition_time,但这种方法对统计类图层的支持稳定性稍弱:
p <- ggplot() + geom_density_2d_filled(data = points, aes(x = x, y = y, alpha = after_stat(level), frame = monthly, cumulative = TRUE)) + geom_sf(data = muns, fill = NA, color = "black") + coord_sf(default_crs = sf::st_crs(3067)) + geom_point(data = points, aes(x = x, y = y, frame = monthly, cumulative = TRUE), alpha = 0.1) + scale_alpha_manual(values = c(0, rep(0.75, 13)), guide = "none") + transition_time(monthly) + labs(title = "Month: {frame_time}") + ease_aes("linear")
内容的提问来源于stack exchange,提问作者Vesanen
相关产品推荐
相关产品推荐

