Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Animation fails when transition_states variable is a factor, but not if it is a character? #434

Closed
saeeshm opened this issue Mar 19, 2021 · 2 comments

Comments

@saeeshm
Copy link

saeeshm commented Mar 19, 2021

Hello,

I have another issue working with the same dataset as #429. As I mentioned, after applying the workaround for "filled" data that I described there, my animation rendered. However, I needed to construct more descriptive labels for each state, so I created a new variable that was a label based on the values of the SES-category variable (included in reprex below).

When the class of this variable is character, the animation works fine. But the order of states is incorrect - it goes from percentile 1 to 5 to percentile 11 to 15, rather than to 6-10 as it should. Arranging the table before creating the animation also has no impact on the order of states in the animation:

popAnim-GAMA

(this is a testing example so it moves quite fast because of having very few frames. The full gif is too big to upload here).

To fix this, I tried turning it into an ordered factor, but when I pass the variable as a factor to SES states the animation fails, with the same error I was receiving in issue #429.

Error in tween_state(as.data.frame(full_set$from), as.data.frame(full_set$to),  : 
  identical(classes, col_classes(to)) is not TRUE

So overall, I can't order the states when states is a character variable, and it fails to animate when it is a factor?

Here is the reprex:

# !usr/bin/env Rscript

# Author: Saeesh Mangwani
# Date: 2021-03-19

# Description: Animation issues for reprex

# ==== Loading libraries ====
library(tidyverse)
library(sf)
#> Linking to GEOS 3.8.0, GDAL 3.0.4, PROJ 6.3.1
library(ragg)
library(reprex)
library(gganimate)
# Script where I define some helper functions for working with my data, including
# the custom theme function I use later (theme_accra)
source("C:/Users/saees/codeProjects/RProjects/accra/accra_viz.R")
#> 
#> Attaching package: 'rlang'
#> The following objects are masked from 'package:purrr':
#> 
#>     %@%, as_function, flatten, flatten_chr, flatten_dbl, flatten_int,
#>     flatten_lgl, flatten_raw, invoke, list_along, modify, prepend,
#>     splice
# Adding a showtext font 'lmroman
library(showtext)
#> Loading required package: sysfonts
#> Loading required package: showtextdb
font_paths(new = "C:/Users/saees/Appdata/Local/Microsoft/Windows/Fonts")
#> [1] "C:\\Users\\saees\\AppData\\Local\\Microsoft\\Windows\\Fonts"
#> [2] "C:\\Windows\\Fonts"
font_add(family = "lmroman", regular = "lmroman10-regular.otf")
showtext_auto()
# ==== Reading data ====

# Reading the census and the shapefile, ensuring only relevant variables are selected
census <- census <- read_csv("C:/Users/saees/codeProjects/RProjects/accra/data/gama/gama20210216_filled.csv")
#> 
#> -- Column specification --------------------------------------------------------
#> cols(
#>   .default = col_double()
#> )
#> i Use `spec()` for the full column specifications.
accra <- read_sf("C:/Users/saees/codeProjects/RProjects/accra/data/shp/GAMA_20200420.shp", query = "SELECT ea_code9ch FROM GAMA_20200420")

# Turning the eacode variable in the census dataset to a string to make joining with the shapefile easier
census <- census %>% 
  mutate(ea_code9ch = str_pad(ea_code9ch, width = 9, side = 'left', pad = '0'))

# Joining data to shapefile
gama <- census %>% 
  inner_join(accra, by = c("ea_code9ch" = "ea_code9ch")) %>% 
  st_as_sf()

# Removing the extra dataset to only keep gama
rm(list = c('census', 'accra'))

# ==== Adding more descriptive labels to the SES cat variable ====

# THe number of percentile groups in the dataset
n_percentiles <- 20
# First splitting a vector of 100 into the number of groups defined above to mimic
# the percentile distribution of SES_cat
percentiles <- split(1:100, sort(rep_len(1:n_percentiles, 100)))
# Turning each list into only a min and max, as that is all we need to construct a
# range label
percentiles <- map(percentiles, ~{ c(min(.x), max(.x))})

# Getting the SES-categories as a vector, and creating a parallel vector of
# labelled names based on it
percentile_labels <- map_chr(as.character(gama$SES_cat_g3), ~ {
  case_when(
    # If the category is not 30 or 40, constructing the label from the right
    # percentile bin
    !(.x %in% c(30, 40)) ~ paste0(percentiles[[.x]][1], "-", percentiles[[.x]][2], "th Percentile"),
    # Otherwise using default labels
    .x == 30 ~ "Students & university residents",
    .x == 40 ~ "Homeless and outdoor sleeper residents"
  )
})

# Getting a correctly ordered factor for the cat labels, based on the order of the
# categorical variable and passing this as the new label variable
gama$SES_cat_labels <- fct_reorder(percentile_labels, as.numeric(gama$SES_cat_g3))

# Illustrating the outcome of this
gama %>% 
  arrange(ea_code9ch, as.numeric(SES_cat_g3)) %>% 
  select(SES_cat_g3, SES_cat_labels) %>% 
  head(n = 10)
#> Simple feature collection with 10 features and 2 fields
#> geometry type:  MULTIPOLYGON
#> dimension:      XY
#> bbox:           xmin: -0.3847607 ymin: 5.484172 xmax: -0.3786746 ymax: 5.488131
#> geographic CRS: WGS 84
#> # A tibble: 10 x 3
#>    SES_cat_g3 SES_cat_labels                                            geometry
#>         <dbl> <fct>                                           <MULTIPOLYGON [°]>
#>  1          1 1-5th Percentile (((-0.3786746 5.486327, -0.3788675 5.486252, -0.~
#>  2          2 6-10th Percenti~ (((-0.3786746 5.486327, -0.3788675 5.486252, -0.~
#>  3          3 11-15th Percent~ (((-0.3786746 5.486327, -0.3788675 5.486252, -0.~
#>  4          4 16-20th Percent~ (((-0.3786746 5.486327, -0.3788675 5.486252, -0.~
#>  5          5 21-25th Percent~ (((-0.3786746 5.486327, -0.3788675 5.486252, -0.~
#>  6          6 26-30th Percent~ (((-0.3786746 5.486327, -0.3788675 5.486252, -0.~
#>  7          7 31-35th Percent~ (((-0.3786746 5.486327, -0.3788675 5.486252, -0.~
#>  8          8 36-40th Percent~ (((-0.3786746 5.486327, -0.3788675 5.486252, -0.~
#>  9          9 41-45th Percent~ (((-0.3786746 5.486327, -0.3788675 5.486252, -0.~
#> 10         10 46-50th Percent~ (((-0.3786746 5.486327, -0.3788675 5.486252, -0.~

# ==== Issue with not rendering when states variable is a factor ====

p <- gama %>% 
  mutate(group = 1L) %>%
  # Removing some EAs and district to only map the relevant area
  filter(district_code %in% c(10304)) %>%
  filter(!(SES_cat_g3 %in% c(30, 40))) %>% 
  # Arranging the data seems to have no impact?
  arrange(ea_code9ch, as.numeric(SES_cat_g3)) %>% 
  # If I turn the variable back to character, the animation renders. Otherwise, it fails:
  # mutate(SES_cat_labels = as.character(SES_cat_labels)) %>% 
  # Enumeration area code, group, median logged income, socio-economic category
  dplyr::select(ea_code9ch, group, ni_num, SES_cat_labels) %>% 
  # Turning population data to a factor to plot it using quintile breaks
  mutate(ni_num = cut(ni_num, breaks = quantile(gama$medlec, probs = seq(0,1,0.2), na.rm = T), ordered_result = T)) %>% 
  # Ensuring it is a factor
  mutate(ni_num = as_factor(ni_num)) %>% 
  # Plotting
  ggplot() +
  geom_sf(aes(fill = ni_num, group = group), colour = "white", size = 0.2) +
  scale_fill_brewer(palette = "OrRd") +
  labs(title = "Median Income: SES Category {closest_frame}",
       subtitle = "Greater Accra Metropolitan Area",
       fill = "Median Income\n(Quantiles)",
       x = NULL,
       y = NULL) +
  # Custom theme that I've made, only edits layout variables like font panel grid, legend, etc.
  theme_accra(theme_font = "lmroman", tscale = 7)

# Transition states (the SES cat variable is grouping factor that defines different socio-economic categories).
anim <- p + transition_states(SES_cat_labels, transition_length = 2, state_length = 2, wrap = T) + exit_fade()

# Using a small number of frames to test whether it's working
anim_save("popAnim-GAMA.gif", 
          animation = anim, 
          device = "ragg_png", width = 6.5, height = 5.5,
          scaling = 0.45, units = "in", res = 300,
          nframes = 20, fps = 10)
#> Error in tween_state(as.data.frame(full_set$from), as.data.frame(full_set$to), : identical(classes, col_classes(to)) is not TRUE

And my session information:

R version 4.0.4 (2021-02-15)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows 10 x64 (build 19042)

Matrix products: default

locale:
[1] LC_COLLATE=English_Canada.1252  LC_CTYPE=English_Canada.1252    LC_MONETARY=English_Canada.1252 LC_NUMERIC=C                    LC_TIME=English_Canada.1252    

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
 [1] reprex_1.0.0    showtext_0.9-2  showtextdb_3.0  sysfonts_0.8.3  knitr_1.31      ragg_1.1.1      gifski_0.8.6    gganimate_1.0.7 ggspatial_1.1.5 tmap_3.3       
[11] sf_0.9-7        forcats_0.5.1   stringr_1.4.0   dplyr_1.0.4     purrr_0.3.4     readr_1.4.0     tidyr_1.1.2     tibble_3.1.0    ggplot2_3.3.3   tidyverse_1.3.0
[21] rlang_0.4.10   

loaded via a namespace (and not attached):
 [1] leafem_0.1.3           colorspace_2.0-0       ellipsis_0.3.1         class_7.3-18           leaflet_2.0.4.1        base64enc_0.1-3        fs_1.5.0              
 [8] dichromat_2.0-0        rstudioapi_0.13        farver_2.1.0           fansi_0.4.2            lubridate_1.7.9.2      xml2_1.3.2             codetools_0.2-18      
[15] jsonlite_1.7.2         tmaptools_3.1-1        broom_0.7.5            dbplyr_2.1.0           png_0.1-7              clipr_0.7.1            compiler_4.0.4        
[22] httr_1.4.2             backports_1.2.1        assertthat_0.2.1       cli_2.3.1              tweenr_1.0.1           htmltools_0.5.1.1      prettyunits_1.1.1     
[29] tools_4.0.4            gtable_0.3.0           glue_1.4.2             Rcpp_1.0.6             jquerylib_0.1.3        cellranger_1.1.0       styler_1.3.2          
[36] raster_3.4-5           vctrs_0.3.6            transformr_0.1.3       leafsync_0.1.0         crosstalk_1.1.1        lwgeom_0.2-5           xfun_0.21             
[43] ps_1.6.0               rvest_0.3.6            lpSolve_5.6.15         lifecycle_1.0.0        pacman_0.5.1           XML_3.99-0.5           scales_1.1.1          
[50] hms_1.0.0              parallel_4.0.4         RColorBrewer_1.1-2     yaml_2.2.1             sass_0.3.1             stringi_1.5.3          highr_0.8             
[57] e1071_1.7-4            pkgconfig_2.0.3        systemfonts_1.0.1.9000 evaluate_0.14          lattice_0.20-41        htmlwidgets_1.5.3      tidyselect_1.1.0      
[64] processx_3.4.5         plyr_1.8.6             magrittr_2.0.1         R6_2.5.0               generics_0.1.0         DBI_1.1.1              pillar_1.5.0          
[71] haven_2.3.1            withr_2.4.1            units_0.7-0            stars_0.5-1            abind_1.4-5            sp_1.4-5               modelr_0.1.8          
[78] crayon_1.4.1           KernSmooth_2.23-18     utf8_1.1.4             rmarkdown_2.7          progress_1.2.2         grid_4.0.4             readxl_1.3.1          
[85] callr_3.5.1            digest_0.6.27          classInt_0.4-3         textshaping_0.3.1      munsell_0.5.0          viridisLite_0.3.0      bslib_0.2.4   
@thomasp85
Copy link
Owner

I think this may have been fixed with the latest tweenr release - can I get you to confirm?

@saeeshm
Copy link
Author

saeeshm commented Mar 25, 2021

Confirmed! Thank you so much :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants