I have data with observations of species at different locations across multiple years. Some years don't have any data. I wanted to create an animated map that included the years for which there's no data, and I succeeded at doing so, but it appears only temporarily.
Here's some reprex:
library(sf)
library(ggplot2)
library(gganimate)
library(transformr)
library(tidyr)
rb <- data.frame(YEAR = c(1995, 2000, 2000, 2001, 2002, 2002, 2002, 2004),
TOTAL = c(5, 10, 8, 14, 15, 12, 16, 15),
LONG = c(runif(8, -80, -78)),
LAT = c(runif(8, 38, 40)))
Filling in the missing years with a random set of coordinates within the range of my coordinates:
rb.zero.df <- data.frame(rb %>%
complete(YEAR = full_seq(1995:2004, 1),
fill = list(LONG = -78.3893,
LAT = 39.63938,
TOTAL = 0)))
rb.zero <- st_as_sf(rb.zero.df, coords = c("LONG", "LAT"), crs = 4326)
Then using ifelse for alpha in aes and shadow_mark to make sure the zero points don't show up:
rb.zero.map <- ggplot() +
geom_sf(data = rb.zero, aes(size = TOTAL, alpha = ifelse(TOTAL == 0, 0, 1))) +
scale_alpha(range = c(0,1)) +
guides(alpha = "none") +
transition_states(YEAR, transition_length = 0, state_length = 1) +
ggtitle("{closest_state}") +
shadow_mark(alpha = ifelse(rb.zero$TOTAL == 0, 0, 0.25))
animate(rb.zero.map)
This used to work, but now it produces this error:
Error in `[[<-.data.frame`(`*tmp*`, i, value = c(0.25, 0, 0, 0, 0, 0.25, :
replacement has 13 rows, data has 12
I don't know how to interpret this error in this context.
If I take the ifelse out of shadow_mark, the code works.
My session info:
R version 4.3.2 (2023-10-31)
Platform: aarch64-apple-darwin20 (64-bit)
Running under: macOS Ventura 13.3.1
Matrix products: default
BLAS: /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBLAS.dylib
LAPACK: /Library/Frameworks/R.framework/Versions/4.3-arm64/Resources/lib/libRlapack.dylib; LAPACK version 3.11.0
locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
time zone: America/New_York
tzcode source: internal
attached base packages:
[1] stats graphics grDevices utils datasets methods base
other attached packages:
[1] transformr_0.1.3 gifski_1.12.0-2 gganimate_1.0.7 tidyr_1.3.0
[5] viridis_0.6.4 viridisLite_0.4.2 spData_2.3.0 dplyr_1.1.4
[9] terra_1.7-65 sf_1.0-15 ggplot2_3.4.4 leaflet.extras2_1.2.2
[13] leaflet_2.2.1 tmap_3.99.9000
loaded via a namespace (and not attached):
[1] DBI_1.2.1 gridExtra_2.3 tmaptools_3.1-1 remotes_2.4.2.1
[5] rlang_1.1.3 magrittr_2.0.3 e1071_1.7-14 compiler_4.3.2
[9] mgcv_1.9-0 png_0.1-8 vctrs_0.6.5 stringr_1.5.1
[13] profvis_0.3.8 pkgconfig_2.0.3 crayon_1.5.2 fastmap_1.1.1
[17] ellipsis_0.3.2 labeling_0.4.3 lwgeom_0.2-13 leafem_0.2.3
[21] utf8_1.2.4 promises_1.2.1 sessioninfo_1.2.2 purrr_1.0.2
[25] cachem_1.0.8 progress_1.2.3 later_1.3.2 tweenr_2.0.2
[29] parallel_4.3.2 prettyunits_1.2.0 R6_2.5.1 stringi_1.8.3
[33] RColorBrewer_1.1-3 pkgload_1.3.4 stars_0.6-4 Rcpp_1.0.12
[37] usethis_2.2.2 base64enc_0.1-3 leaflet.providers_2.0.0 Matrix_1.6-1.1
[41] httpuv_1.6.13 splines_4.3.2 tidyselect_1.2.0 rstudioapi_0.15.0
[45] dichromat_2.0-0.1 abind_1.4-5 codetools_0.2-19 miniUI_0.1.1.1
[49] pkgbuild_1.4.3 lattice_0.21-9 tibble_3.2.1 leafsync_0.1.0
[53] plyr_1.8.9 shiny_1.8.0 withr_3.0.0 units_0.8-5
[57] proxy_0.4-27 urlchecker_1.0.1 lpSolve_5.6.20 pillar_1.9.0
[61] KernSmooth_2.23-22 generics_0.1.3 sp_2.1-2 hms_1.1.3
[65] munsell_0.5.0 scales_1.3.0 xtable_1.8-4 class_7.3-22
[69] glue_1.7.0 tools_4.3.2 leaflegend_1.2.0 data.table_1.14.10
[73] fs_1.6.3 XML_3.99-0.16.1 grid_4.3.2 crosstalk_1.2.1
[77] devtools_2.4.5 colorspace_2.1-0 nlme_3.1-163 cols4all_0.7
[81] raster_3.6-26 cli_3.6.2 fansi_1.0.6 gtable_0.3.4
[85] digest_0.6.34 widgetframe_0.3.1 classInt_0.4-10 htmlwidgets_1.6.4
[89] farver_2.1.1 memoise_2.0.1 htmltools_0.5.7 lifecycle_1.0.4
[93] mime_0.12
I have no clue why this code previously worked and now doesn't - the data and the code are the same. I'd appreciate thoughts on this and/or alternate solutions to the missing years problem. Thank you!
TL;DR
Use
instead of
Preface
When I tried your example I got a different error:
But this seems to be a bug in gganimate and the temporary fix was to remove the
crsaltogether.Explanation of the issue
To your problem at hand, you are using
shadow_marknot in its intended way. If you debug thetrainfunction ofShadowMark(debug(get("train", ShadowMark))) you will see that whatever you pass toshadow_markwill be evaluated in the context of the data slice which is shown in the current animation step.I am not deep into the internals of
gganimatebut apparently they split the original data for each slice and do their magic.The important bit is, that at a certain step the "current" data is just a subset of the whole dataset (enriched with aesthetics data), that is, it contains only a subset of the original rows.
In this context evaluating
ifelse(rb.zero$TOTAL == 0, 0, 0.25))does not make sense, because it evaluates always to a vector of lengthnrow(rb.zero.df)(=13) which may result in the error you are seeing, especially when the current data slice is only 12 rows long (whileifelse(rb.zero$TOTAL == 0, 0, 0.25)is always 13 elements long).N.B. The mean thing is that for certain combinations you do not see the error immediately because of
R'srecycling rules, only if the lengths are not compatible (typically not being a multiple of each other) the error is thrown. This, by the way, may explain why you did not see the error for certain combinations, because it happened to result always in compatible lengths.Solution
Having said that, the way
shadow_markis supposed to be used, is to supply the names ofaestheticsas parameters. This works, becauseshadow_markuses quosures, that is it evaluates its parameters later and in the right context. The context is the data slice mentioned before, where there is aalphaslot in the aesthetics enriched data slice (as you defined this aesthatic).Long story short you should create your plot like this: