geom_sf 使用 coord_sf 指定 xlim、ylim 时填充失败。尝试使用 av 包创建动画时寻找解决方法

geom_sf fill fails when xlim, ylim are specified using coord_sf. Looking for a workaround when trying to create an animation using the av package

ggplot2 存在一个已知问题,在使用 coord_sf 指定 xlimylim 时,geom_sf 函数并不总是正常工作。这个问题似乎是 Windows 特有的,当前的解决方法是将绘图保存为 .png。 See GitHub link: geom_sf fill missing when xlim,ylim set in coord_sf

我遇到的问题是我不是要制作静态图,而是要使用 av 包将数百个图拼接在一起的动画。

基本上,我正在寻求帮助来实施合适的解决方法,并且不需要保存或调用单个 .png 文件。

如有任何想法或建议,我们将不胜感激。

下图显示了我解决这个问题的动机,绘制了飓风随时间变化的轨迹。

Whosebug 不允许对视频进行 post 编辑,因此如果您想查看我的可重现代码的输出,您可以在此处查看我的原始 GitHub post可以在这里找到... geom_sf, fill missing when xlim, ylim set in coord_sf in windows (follow-up to #3283) #4306

library(tidyverse)
library(sf)
library(av)

tracts <- read_sf("https://opendata.arcgis.com/datasets/230f9d23f6874be983901876cd600c4e_0.geojson") %>% 
  select(
    geometry,
    ALAND10,
    GEOID10
    )
st_crs(tracts)

set.seed(264)

v1 <- runif(1:dim(tracts)[1], .7, 1.25)

tracts2 <- cbind(tracts, v1)

tracts_2017 <- tracts2 %>%
  mutate(season=2017)

tracts_2018 <- tracts2 %>%
  mutate(
    season=2018,
    ALAND10 = ALAND10*v1
    )
tracts3 <- rbind(tracts_2017, tracts_2018) 
  st_crs(tracts3)

makeplot1 <- function(){
  datalist1 <- split(
    tracts3,
    tracts3$season
  )
  datalist2 <- split(
    tracts3,
    tracts3$season
  )
  mapply(function(data1, data2){
    p1 <- ggplot() + 
      geom_sf(
        data = data1,
        aes(fill = ALAND10)
      ) +
      geom_sf(
        data = data2 %>% st_union(),
        fill = alpha("red", 0.4),
        color = alpha("red", 0.4)
      ) +
      coord_sf(
        ylim = c( 43.04, 43.07),
        xlim = c(-76.14,-76.10),
        clip = "on",
        expand = F
      )
    print(p1)
    
    },
    datalist1, datalist2
  ) 
}

makeplot2 <- function(){
  datalist1 <- split(
    tracts3,
    tracts3$season
  )
  datalist2 <- split(
    tracts3,
    tracts3$season
  )
  mapply(function(data1, data2){
    p2 <- ggplot() + 
      geom_sf(
        data = data1,
        aes(fill = ALAND10)
      ) +
      geom_sf(
        data = data2 %>% st_union(),
        fill = alpha("red", 0.4),
        color = alpha("red", 0.4)
      ) 
    print(p2)
    
  },
  datalist1, datalist2
  ) 
}

video_file1 <- file.path(tempdir(), 'Tracts1.mp4')
av::av_capture_graphics(makeplot1(), video_file1, vfilter='framerate=fps=10')
av::av_media_info(video_file1)
utils::browseURL(video_file1)

video_file2 <- file.path(tempdir(), 'Tracts2.mp4')
av::av_capture_graphics(makeplot2(), video_file2, vfilter='framerate=fps=10')
av::av_media_info(video_file2)
utils::browseURL(video_file2)

正如 Thomas Lin Pedersen 在您链接的 github 问题中所建议的那样,解决方案是在 Windows 机器上使用 png(..., type = 'cairo') 设备。如果您阅读 ?av::av_capture_graphics() 上的文档,您会发现 ... 参数可用于将参数传递给 png() 函数。因此,我建议完全这样做:

library(tidyverse)
library(sf)
library(av)

tracts <- read_sf("https://opendata.arcgis.com/datasets/230f9d23f6874be983901876cd600c4e_0.geojson") %>% 
  select(
    geometry,
    ALAND10,
    GEOID10
  )
st_crs(tracts)

set.seed(264)

v1 <- runif(1:dim(tracts)[1], .7, 1.25)

tracts2 <- cbind(tracts, v1)

tracts_2017 <- tracts2 %>%
  mutate(season=2017)

tracts_2018 <- tracts2 %>%
  mutate(
    season=2018,
    ALAND10 = ALAND10*v1
  )
tracts3 <- rbind(tracts_2017, tracts_2018) 
st_crs(tracts3)

makeplot1 <- function(){
  datalist1 <- split(
    tracts3,
    tracts3$season
  )
  datalist2 <- split(
    tracts3,
    tracts3$season
  )
  mapply(function(data1, data2){
    p1 <- ggplot() + 
      geom_sf(
        data = data1,
        aes(fill = ALAND10)
      ) +
      geom_sf(
        data = data2 %>% st_union(),
        fill = alpha("red", 0.4),
        color = alpha("red", 0.4)
      ) +
      coord_sf(
        ylim = c( 43.04, 43.07),
        xlim = c(-76.14,-76.10),
        clip = "on",
        expand = F
      )
    print(p1)
    
  },
  datalist1, datalist2
  ) 
}

video_file1 <- file.path(tempdir(), 'Tracts1.mp4')
av::av_capture_graphics(makeplot1(), video_file1, 
                        vfilter='framerate=fps=10',
                        type = "cairo")
av::av_media_info(video_file1)
utils::browseURL(video_file1)

此外,

the current work around involves saving the plot as a .png.

正是av::av_capture_graphics()在幕后所做的,也是gganimate包所做的。

最后,我建议您对色标设置固定限制,因为这似乎在帧之间发生变化,使任何解释都变得复杂。 gganimate 包优雅地说明了这些细节。