Possible to animate polygon fill using gganimate in R?

不打扰是莪最后的温柔 提交于 2021-02-18 17:04:21

问题


I have county level data recording the year an invasive insect pest was first detected in that county between 2002 and 2018. I created a map using ggplot2 and the maps package that fills the county polygons with a color according to the year the pest was detected.

**Is there a way to use the gganimate package to animate this map with the first frame filling in only polygons with a detection date of 2002, the second frame filling polygons with a detection date of 2003 or earlier (so 2002 and 2003), a third frame for detection dates of 2004 or earlier (2002, 2003, 2004), etc.? ** Clarification: I'd like it so all the county polygons are always visible and filled in with white initially and each frame of the animation adds fills in counties based on the year of detection.

I've tried using the transition_reveal(data$detect_year) with the static plot but get an error that "along data must either be integer, numeric, POSIXct, Date, difftime, orhms".

Here's some code for a reproducible example:

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)

If it's possible to do this with gganimate, I'd like to but I'm also open to other solutions if anyone has ideas.


回答1:


After getting an answer from @RLave that almost did what I wanted and spending a little time with the documentation, I was able to figure out a way to do what I want. It doesn't seem very clean, but it works.

Essentially, I created a copy of my data frame for each year that needed a frame in the animation. Then for each year of detection I wanted to animate, I edited the detection_year variable in that copy of the data frame so that any county that had a detection in the year of interest or earlier retained their values and any county that had no detection yet was converted to the value I plotted as white. This made sure all the counties were always plotted. Then I needed to use transition_manual along with a unique ID I gave to each copy of the original data frame to determine the order of the animation.

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




回答2:


Possibily this, but I'm not sure that this is the expected output.

I changed your code, probably you don't need to split. I used group_by to assign a year to each region.

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))

For the transition you need to define the id, here the same as the grouping (subregion or group) and a correct date format for the transition (along) variable (I used 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

Does this do it for you?



来源:https://stackoverflow.com/questions/54991039/possible-to-animate-polygon-fill-using-gganimate-in-r

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!