R - tmap_animation 生成带绿框的 gif

R - tmap_animation generates gif with green frames

我正在尝试使用 tmap 创建动画 GIF 并将其显示在我的 Shiny 应用程序中。当我对单个日期使用 tm_shape() + tm_polygons() 时,生成的图像始终正常。但是,当我使用 tm_facets() 并将结果提供给 tmap_animation 时,生成的 GIF 具有随机的深绿色帧,如下所示。

这是我使用的生成动画的代码:

data(World)

confirmed = read.csv('./data/time_series_covid_19_confirmed.csv', stringsAsFactors = T) %>%
  select(-Province.State, -Country.Region) %>%
  pivot_longer(!c('Lat', 'Long', 'iso3'), names_to = 'date', values_to = 'confirmed') %>%
  mutate(date = as.Date(gsub('X', '', date), '%m.%d.%Y')) %>%
  group_by(iso3, date) %>%
  summarise(confirmed = sum(confirmed)) %>%
  mutate(perc_change = 100 * ifelse(
      lag(confirmed, default = 0) == 0 | confirmed < 1000 | lag(confirmed) > confirmed, 
      0, 
      (confirmed - lag(confirmed)) / lag(confirmed)
    )
  ) %>%
  inner_join(select(World, iso_a3, geometry), by=c('iso3' = 'iso_a3')) %>%
  st_sf()

conf_anim = confirmed %>%
  filter(date < '2020-02-28') %>%
  tm_shape() + tm_polygons('perc_change', style='cont') +
  # tm_fill('perc_change', palette='Blues', style='fixed', 
  #         breaks=c(0, 5, 10, 15, 20, 25, 30, 35, 40, 45, Inf)) + tm_borders() +
  tm_facets(along='date', free.coords = F)

tmap_animation(conf_anim, filename = './www/conf_anim.gif', delay=50)

有人知道我该如何解决这个问题吗?

我遇到了同样的问题。 tmap GitHub 问题选项卡上的 I asked about it,团队将其追溯到 gifskitmap 用于生成 gif 动画的问题。我发现在不使用 tmap.

的情况下使用 gifski 制作的动画也会发生同样的事情

mtennekes 目前建议的解决方法是将动画保存为 mp4 而不是 gif,后者使用 av 包:

tmap_animation(conf_anim, filename = './www/conf_anim.mp4', delay=50)

不是一个完整的修复,但希望它对您的即时应用有所帮助。

以防其他人遇到这个问题,我可以使用 tmap、gifski(tmap 用来生成 GIF)、dplyr 和 png 库创建一个解决方法。 此方法速度不快,并且以这种方式生成 GIF 可能需要很长时间。 提到的另一个答案是使用 MP4 格式而不是 GIF - 如果您可以选择此方法,则此方法要快得多.

假设您有一个名为 df_sf 的 sf 对象,您正试图沿着 facet_along_col_str 切面,并且tm_polygons 的第一个参数是 polygon_col_str,这里是帮助您生成 GIF 的代码:

library(tmap)
library(gifski)
library(png)
library(dplyr)

generate_gif = function(sf_df, facet_along_col_str, polygon_col_str, gif_file, delay) {
  dims = get_dims(sf_df, facet_along_col_str, polygon_col_str)
  save_gif(get_maps(sf_df), height=dims[1], width=dims[2], delay=delay, gif_file=gif_file)
}

get_dims = function(sf_df, facet_along, polygon_col) {
  slice = st_drop_geometry(select(sf_df, !!as.symbol(map_slice_col)))[[1]][1]
  t = tm_shape(filter(sf_df, !!as.symbol(map_slice_col) == slice)) +
    tm_polygons(polygons_col)
  filename = tempfile(fileext='.png')
  tmap_save(t, filename=filename)
  dims = dim(readPNG(filename))
  file.remove(filename)

  return(dims)
}

get_maps = function(sf_df, facet_along, polygon_col) {
  slices = st_drop_geometry(select(sf_df, !!as.symbol(map_slice_col)))[[1]]
  slices = sort(unique(slices))
  for (i in 1:length(slices)) {
    t = tm_shape(filter(sf_df, !!as.symbol(facet_along) == slices[i])) +
      tm_polygons(polygon_col)
    print(t)
  }
}