thomasp85 / gganimate

A Grammar of Animated Graphics
https://gganimate.com
Other
1.95k stars 310 forks source link

Intermittent failure in animating sf polygons #279

Closed clauswilke closed 3 years ago

clauswilke commented 5 years ago

I'm trying to animate transitions between sf polygons, and I'm observing that the animation code often (but not always) fails. Apologies for the somewhat lengthy reprex.

If I run this code multiple times, sometimes some of the animations render appropriately. Also, when they fail, the error message changes. (The isobanding algorithm is not guaranteed to return the exact same arrangement of polygon coordinates every time, so this may be part of the reason.) I ran the reprex three times to demonstrate this. I have seen the final animation succeed on occasion, but most of the time it fails.

Run 1

library(magick)
#> Linking to ImageMagick 6.9.9.39
#> Enabled features: cairo, fontconfig, freetype, lcms, pango, rsvg, webp
#> Disabled features: fftw, ghostscript, x11
library(sf)
#> Linking to GEOS 3.6.1, GDAL 2.1.3, PROJ 4.9.3
library(ggplot2)
library(gganimate)
library(isoband)  # devtools::install_github("clauswilke/isoband")

sf_from_image <- function(image) {
  image_gray <- image %>% image_quantize(colorspace = "gray")
  image_raster <- as.raster(image_gray)
  d <- dim(image_raster)
  m <- matrix(c((255-col2rgb(image_raster)[1,])), nrow = d[1], ncol = d[2], byrow = TRUE)
  b <- isobands(1:d[2], d[1]:1, m, c(-1, 20, 40), c(20, 40, 256))
  bands <- iso_to_sfg(b)
  data <- st_sf(
    level = letters[1:length(bands)],
    geometry = st_sfc(bands)
  )
}

img1 <- image_resize(magick::logo, "300x300")
img2 <- image_resize(image_read("https://jeroen.github.io/images/Rlogo.png"), "300x300")
img1_sf <- sf_from_image(img1)
img2_sf <- sf_from_image(img2)

img1_sf$type = "magick"
img2_sf$type = "R"
data <- rbind(img1_sf, img2_sf)
plot_base <- ggplot(data) + 
  geom_sf(aes(fill = level), color = NA) + 
  scale_fill_grey(start = 0.95, end = 0.35, guide = "none") +
  theme_bw()

# works always
plot_base + facet_wrap(~type)


# works sometimes
plot_base + transition_states(type, 0, 1) 
#> Error in `$<-.data.frame`(`*tmp*`, "x", value = c(63.7830312762083, 64.5949254195239, : replacement has 4 rows, data has 0

# works sometimes
plot_base + transition_states(type, 1, 1) 
#> Error in `$<-.data.frame`(`*tmp*`, "x", value = c(58.9056096408043, 68.0800590636226, : replacement has 4 rows, data has 0

Created on 2019-01-24 by the reprex package (v0.2.1)

Run 2

library(magick)
#> Linking to ImageMagick 6.9.9.39
#> Enabled features: cairo, fontconfig, freetype, lcms, pango, rsvg, webp
#> Disabled features: fftw, ghostscript, x11
library(sf)
#> Linking to GEOS 3.6.1, GDAL 2.1.3, PROJ 4.9.3
library(ggplot2)
library(gganimate)
library(isoband)  # devtools::install_github("clauswilke/isoband")

sf_from_image <- function(image) {
  image_gray <- image %>% image_quantize(colorspace = "gray")
  image_raster <- as.raster(image_gray)
  d <- dim(image_raster)
  m <- matrix(c((255-col2rgb(image_raster)[1,])), nrow = d[1], ncol = d[2], byrow = TRUE)
  b <- isobands(1:d[2], d[1]:1, m, c(-1, 20, 40), c(20, 40, 256))
  bands <- iso_to_sfg(b)
  data <- st_sf(
    level = letters[1:length(bands)],
    geometry = st_sfc(bands)
  )
}

img1 <- image_resize(magick::logo, "300x300")
img2 <- image_resize(image_read("https://jeroen.github.io/images/Rlogo.png"), "300x300")
img1_sf <- sf_from_image(img1)
img2_sf <- sf_from_image(img2)

img1_sf$type = "magick"
img2_sf$type = "R"
data <- rbind(img1_sf, img2_sf)
plot_base <- ggplot(data) + 
  geom_sf(aes(fill = level), color = NA) + 
  scale_fill_grey(start = 0.95, end = 0.35, guide = "none") +
  theme_bw()

# works always
plot_base + facet_wrap(~type)


# works sometimes
plot_base + transition_states(type, 0, 1) 


# works sometimes
plot_base + transition_states(type, 1, 1) 
#> Error in `$<-.data.frame`(`*tmp*`, "x", value = c(35.7224507053282, 30.8160621337182, : replacement has 3 rows, data has 0

Created on 2019-01-24 by the reprex package (v0.2.1)

Run 3

library(magick)
#> Linking to ImageMagick 6.9.9.39
#> Enabled features: cairo, fontconfig, freetype, lcms, pango, rsvg, webp
#> Disabled features: fftw, ghostscript, x11
library(sf)
#> Linking to GEOS 3.6.1, GDAL 2.1.3, PROJ 4.9.3
library(ggplot2)
library(gganimate)
library(isoband)  # devtools::install_github("clauswilke/isoband")

sf_from_image <- function(image) {
  image_gray <- image %>% image_quantize(colorspace = "gray")
  image_raster <- as.raster(image_gray)
  d <- dim(image_raster)
  m <- matrix(c((255-col2rgb(image_raster)[1,])), nrow = d[1], ncol = d[2], byrow = TRUE)
  b <- isobands(1:d[2], d[1]:1, m, c(-1, 20, 40), c(20, 40, 256))
  bands <- iso_to_sfg(b)
  data <- st_sf(
    level = letters[1:length(bands)],
    geometry = st_sfc(bands)
  )
}

img1 <- image_resize(magick::logo, "300x300")
img2 <- image_resize(image_read("https://jeroen.github.io/images/Rlogo.png"), "300x300")
img1_sf <- sf_from_image(img1)
img2_sf <- sf_from_image(img2)

img1_sf$type = "magick"
img2_sf$type = "R"
data <- rbind(img1_sf, img2_sf)
plot_base <- ggplot(data) + 
  geom_sf(aes(fill = level), color = NA) + 
  scale_fill_grey(start = 0.95, end = 0.35, guide = "none") +
  theme_bw()

# works always
plot_base + facet_wrap(~type)


# works sometimes
plot_base + transition_states(type, 0, 1) 
#> Error in `$<-.data.frame`(`*tmp*`, "x", value = c(235.843899231276, 212.962400444976, : replacement has 4 rows, data has 0

# works sometimes
plot_base + transition_states(type, 1, 1) 
#> Error in `$<-.data.frame`(`*tmp*`, "x", value = c(126.114895598228, 128.851368374646, : replacement has 5 rows, data has 0

Created on 2019-01-24 by the reprex package (v0.2.1)

clauswilke commented 5 years ago

Some additional insight: Just executing the last line plot_base + transition_states(type, 1, 1) multiple times will eventually lead to success. So the nondeterministic behavior seems to live in gganimate. And, here is an example where I was successful with the last animation, to show it works. I reduced the image resolution to 70x70 to be able to iterate more quickly.

animation

thomasp85 commented 5 years ago

I’m quite sure it has something to do with the tessalation done in transformr

thomasp85 commented 3 years ago

I don't seem to be able to reproduce this any more so I'm closing - feel free to ping me if it remains a problem