Search code examples
rggplot2shapefilergdalgganimate

Using ggplot to plot shapefile and gganimate for animation


Sample data

library(raster)
library(ggplot2)

my.shp <- getData('GADM', country = 'FRA', level = 1)
plot(my.shp)

enter image description here

If I want to plot this data using ggplot:

my.shp_f <- fortify(my.shp, region = "ID_1")
ggplot(data = my.shp_f, aes(long, lat, group = group)) + geom_polygon(fill = "grey80")

enter image description here

Question 1: Why has administrative boundary disappeared?

Question 2: I have another dataframe which has 2 years of daily rainfall data from day 1 to day 365 of for each of the administrative divisions.

rain.data <- data.frame(ID_1 = rep(my.shp@data$ID_1, each = 2 * 365),
                        year = rep(rep(1981:1982, each = 365), times = 2),
                        day = rep(1:365, times = 4),
                        rain = sample(1:20, replace = T, 2 * 365 * 2))

I want to create an animation of daily rainfall for this shape file going from day 1 1981 to day 365 1982.

My overall approach at the moment is to make a loop and save rainfall map of each day as individual .png file and then stack those files as .gif. However, this results in me saving 2 years X 365 days worth of .png files first and then stack them together. If I have 30 years worth of data, this becomes impossible. I read this post about gganimate https://github.com/thomasp85/gganimate and wondered if someone can demonstrate how to generate an animated map using gganimate using the data above


Solution

  • This answer is steering things a little bit in a different direction but I've wanting to try gganimate and this was a good excuse. My modifications are primarily by using the sf package and the new geom_sf Geom from ggplot2. I don't love the hacky date fixing so that certainly could be improved. I also only plotted a subset of the Dates - the amount of data you have will likely take some time depending on your setup. Anyways here is what I would do:

    library(raster)
    library(ggplot2)
    library(sf)
    library(dplyr)
    library(lubridate)
    library(gganimate)
    library(rmapshaper)
    
    my.shp <- getData('GADM', country = 'FRA', level = 1)
    
    ## Convert the spatial file to sf
    my.shp_sf <- st_as_sf(my.shp) %>% 
      ms_simplify()
    
    ## Here is how to plot without the rain data
    ggplot(my.shp_sf) +
      geom_sf()
    
    ## Convert your data into a date
    ## this is very hacky and coule be improved
    rain.data <- data.frame(ID_1 = rep(my.shp@data$ID_1, each = 2 * 365),
                            year = rep(rep(1981:1982, each = 365), times = 2),
                            day = rep(1:365, times = 4),
                            rain = sample(1:20, replace = T, 2 * 365 * 2)) 
    
    date_wo_year <- as.Date(rain.data$day -1, origin = "1981-01-01")
    rain.data$Date = ymd(paste0(rain.data$year, "-",month(date_wo_year),"-", day(date_wo_year)))
    
    ## Join the rain.data with a properly formatted date with the spatial data. 
    joined_spatial <- my.shp_sf %>% 
      left_join(rain.data)
    
    ## Plot the spatial data and create an animation
    joined_spatial %>% 
      filter(Date < as.Date("1981-02-28")) %>% 
      ggplot() +
      geom_sf(aes(fill = rain)) +
      scale_fill_viridis_c() +
      theme_void() +
      coord_sf(datum = NA) +
      labs(title = 'Date: {current_frame}') +
      transition_manual(Date)