可以在 R 中使用 gganimate 对多边形填充进行动画处理吗?

Possible to animate polygon fill using gganimate in R?

我有县级数据记录了 2002 年至 2018 年间该县首次检测到入侵性害虫的年份。我使用 ggplot2 和地图包创建了一张地图,该地图根据年份用颜色填充县多边形检测到有害生物。

** 有没有一种方法可以使用 gganimate 包来制作这张地图的动画,第一帧只填充检测日期为 2002 年的多边形,第二帧填充检测日期为 2003 年或更早的多边形(所以2002 年和 2003 年),检测日期为 2004 年或更早(2002 年、2003 年、2004 年)的第三帧,等等? ** 澄清:我希望所有县多边形始终可见并最初用白色填充,并且动画的每一帧都会根据检测年份添加县填充。

我试过将 transition_reveal(data$detect_year) 与静态图一起使用,但出现 "along data must either be integer, numeric, POSIXct, Date, difftime, orhms".

错误

下面是一些可重现示例的代码:

library(dplyr)
library(purrr)
library(maps)
library(ggplot2)
library(gganimate)
# Reproducible example
set.seed(42)
map_df <- map_data("county") %>% 
   filter(region == "minnesota")
map_df$detection_year <- NA
# Add random detection year to each county
years <- 2002:2006
map_list <- split(map_df, f = map_df$subregion)
map_list <- map(map_list, function(.x) {
   .x$detection_years <- mutate(.x, detection_years = sample(years, 1))
})
# collapse list back to data frame
map_df <- bind_rows(map_list)
map_df$detection_years <- as.factor(map_df$detection_years)

# Make plot
static_plot <- ggplot(map_df,
                      aes(x = long,
                          y = lat,
                          group = group)) +
   geom_polygon(data = map_df, color = "black", aes(fill = detection_years)) +
   scale_fill_manual(values = terrain.colors(n = length(unique(map_df$detection_years))),
                     name = "Year EAB First Detected") +
   theme_void() +
   coord_fixed(1.3)

animate_plot <- static_plot +
   transition_reveal(detection_years)

如果可以用 gganimate 做到这一点,我愿意,但如果有人有想法,我也愿意接受其他解决方案。

可能是这样,但我不确定这是预期的输出。

我更改了您的代码,可能您不需要 split。我使用 group_by 为每个地区分配了年份。

set.seed(42)
years <- 2002:2006

map_df <- map_data("county") %>% 
  filter(region == "minnesota")

map_df <- map_df %>% 
  group_by(subregion) %>% 
  mutate(detection_year = sample(years,1))

对于转换,您需要定义 id,此处与分组(subregiongroup)相同,并为转换定义正确的日期格式(along) 变量(我用 lubridate::year())

# Make plot
static_plot <- ggplot(map_df,
                      aes(x = long,
                          y = lat,
                          group = group)) +
  geom_polygon(color = "black", aes(fill = as.factor(detection_year))) +
  scale_fill_manual(values = terrain.colors(n = length(unique(map_df$detection_year))),
                    name = "Year EAB First Detected") +
  theme_void() +
  coord_fixed(1.3)

animate_plot <- static_plot +
  transition_reveal(subregion, # same as the group variable
                    lubridate::year(paste0(detection_year, "-01-01"))) # move along years

这个适合你吗?

在从@RLave 得到几乎可以满足我要求的答案并花一点时间阅读文档后,我找到了一种方法来满足我的要求。看起来不是很干净,但是可以用。

基本上,我为动画中需要帧的每一年都创建了数据帧的副本。然后,对于我想要制作动画的每一年的检测,我编辑了数据框副本中的 detection_year 变量,以便在感兴趣的年份或更早的年份进行检测的任何县都保留其值,并且任何县都有尚未检测到转换为我绘制为白色的值。这确保始终绘制所有县。然后我需要使用 transition_manual 以及我为原始数据帧的每个副本提供的唯一 ID 来确定动画的顺序。

library(dplyr)
library(purrr)
library(maps)
library(ggplot2)
library(gganimate)
# Reproducible example
set.seed(42)
years <- 2002:2006

map_df <- map_data("county") %>% 
   filter(region == "minnesota")

map_df <- map_df %>% 
   group_by(subregion) %>% 
   mutate(detection_year = sample(years,1))

animate_data <- data.frame()
for(i in 2002:2006){
   temp_dat <- map_df %>% 
      mutate(detection_year = as.numeric(as.character(detection_year))) %>% 
      mutate(detection_year = case_when(
         detection_year <= i ~ detection_year,
         detection_year > i ~ 2001
      ),
      animate_id = i - 2001
      )
   animate_data <- bind_rows(animate_data, temp_dat)
}

animate_data$detection_year <- as.factor(as.character(animate_data$detection_year))

# Make plot
static_plot <- ggplot(animate_data,
                      aes(x = long,
                          y = lat,
                          group = group)) +
   geom_polygon(data = animate_data, color = "black", aes(fill = detection_year)) +
   scale_fill_manual(values = c("white",
                                terrain.colors(n = 5)),
                     name = "Year First Detected") +
   theme_void() +
   coord_fixed(1.3) #+
   facet_wrap(~animate_id)

animate_plot <- static_plot +
   transition_manual(frames = animate_id)
animate_plot