geom_sf/gganimate/shadow_mark代码报‘Replacement has x rows’错误求助
问题描述
我有多物种在不同地点的多年份观测数据,部分年份无数据,想要制作包含无数据年份的动画地图,此前成功实现但现在失效。以下是可复现代码及错误信息:
可复现代码
数据准备
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)))
填充缺失年份数据
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)
动画地图代码
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)
错误信息
Error in `[[<-.data.frame`(`*tmp*`, i, value = c(0.25, 0, 0, 0, 0, 0.25, : replacement has 13 rows, data has 12
移除shadow_mark中的ifelse后代码可正常运行,数据和代码未变更,不知为何失效,恳请排查原因或提供替代方案。
会话信息
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
原因分析与解决方案
错误原因
shadow_mark在配合transition_states生成动画时,会自动扩展数据集以包含历史状态的元素。直接引用原始数据的ifelse(rb.zero$TOTAL == 0, 0, 0.25)会导致长度不匹配——原始数据有12行,但动画帧处理后的数据行数变为13,触发维度错误。
替代方案
不要直接在shadow_mark中传入原始数据的向量,而是通过映射美学变量的方式控制透明度,让gganimate自动适配数据长度:
方案1:提前在数据中添加阴影透明度列
# 给rb.zero新增shadow_alpha列 rb.zero$shadow_alpha <- ifelse(rb.zero$TOTAL == 0, 0, 0.25) # 动画代码中映射该列到shadow_mark的alpha参数 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(aes(alpha = shadow_alpha)) animate(rb.zero.map)
方案2:在shadow_mark中直接使用条件映射
直接在shadow_mark的aes内编写条件逻辑,让gganimate基于当前帧的数据计算透明度:
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(aes(alpha = ifelse(TOTAL == 0, 0, 0.25))) animate(rb.zero.map)
说明
两种方案都能让gganimate自动适配动画帧的数据长度,避免维度不匹配问题。方案1适合提前处理复杂逻辑,方案2更简洁,适合简单条件判断。
内容的提问来源于stack exchange,提问作者Molly Cohn
相关产品推荐
相关产品推荐

