ggplotly渲染ggplot2热图时单值行显示异常灰色问题
问题描述
使用ggplot2与plotly包绘制热图时存在边界场景异常:当热图某一行的填充值为单一固定值时,原生ggplot输出效果符合预期,但经ggplotly()转换渲染后,该行所有单元格均显示为异常灰色,疑似包功能缺陷。
问题复现代码
library(ggplot2) library(plotly) theme_set(theme_gray()) PROBS <- c(50, 60, 70, 80, 90, 95, 100) gradientPalette <- colorRampPalette(c("#5cd400", "#fff100", "#d4000f"), bias = .25) set.seed(1) data <- data.frame( x = rep(seq(1, 100), 2), y = c(rep("V1", 100), rep("V2", 100)), z = c(sample(PROBS, 100, replace = T, prob = 1.01 - PROBS/100), rep(50, 100)), group = c(rep("G1", 100), rep("G2", 100)) ) p <- data %>% ggplot(aes(x, y)) + geom_tile(aes(fill = z)) + facet_wrap(~ group, nrow = 2, scales = "free_y") + scale_fill_gradientn(name = NULL, colours = gradientPalette(length(PROBS) + 1), limits = c(20, 100), breaks = PROBS*100, labels = PROBS*100) # 原生ggplot输出 p # 转换后plotly输出 ggplotly(p)
效果对比
- ggplot原生输出效果:

- ggplotly异常输出效果:

运行环境信息
R version 4.1.3 (2022-03-10) Platform: x86_64-pc-linux-gnu (64-bit) Running under: Ubuntu 20.04.4 LTS Matrix products: default BLAS: /usr/lib/x86_64-linux-gnu/openblas-pthread/libblas.so.3 LAPACK: /usr/lib/x86_64-linux-gnu/openblas-pthread/liblapack.so.3 locale: [1] LC_CTYPE=en_US.UTF-8 LC_NUMERIC=C LC_TIME=en_US.UTF-8 LC_COLLATE=en_US.UTF-8 LC_MONETARY=en_US.UTF-8 [6] LC_MESSAGES=en_US.UTF-8 LC_PAPER=en_US.UTF-8 LC_NAME=C LC_ADDRESS=C LC_TELEPHONE=C [11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C attached base packages: [1] stats graphics grDevices datasets utils methods base other attached packages: [1] plotly_4.9.4.1 ggplot2_3.3.5 loaded via a namespace (and not attached): [1] pillar_1.6.1 compiler_4.1.3 tools_4.1.3 digest_0.6.27 jsonlite_1.7.2 lifecycle_1.0.0 tibble_3.1.2 [8] gtable_0.3.0 viridisLite_0.4.0 pkgconfig_2.0.3 rlang_0.4.11 crosstalk_1.1.1 yaml_2.2.1 withr_2.4.2 [15] dplyr_1.0.7 httr_1.4.2 generics_0.1.0 vctrs_0.3.8 htmlwidgets_1.5.3 grid_4.1.3 tidyselect_1.1.1 [22] glue_1.4.2 data.table_1.14.2 R6_2.5.0 fansi_0.5.0 purrr_0.3.4 tidyr_1.1.3 farver_2.1.0 [29] magrittr_2.0.1 scales_1.1.1 ellipsis_0.3.2 htmltools_0.5.1.1 colorspace_2.0-2 renv_0.13.2 labeling_0.4.2 [36] utf8_1.2.1 lazyeval_0.2.2 munsell_0.5.0 crayon_1.4.1
问题原因与修复方案
这是plotly 4.9.x版本的已知转换缺陷:ggplotly在处理分面场景的色阶映射时,默认会为每个分面单独计算填充值的取值范围。当某一分面/行的填充值完全为固定常数时,色阶计算会得到极差为0的无效结果,无法完成颜色映射,最终回退显示为默认灰色。
可选择以下任意一种方式修复:
- 升级plotly包至4.10.0及以上稳定版本。该边界场景问题已在高版本中完成兼容,转换时会直接读取ggplot全局设置的
limits参数做统一色阶映射,不再单独为分面计算色阶范围,转换后效果与原生ggplot完全一致。 - 若暂时无法升级包,可在
ggplotly调用后手动强制指定全局色阶规则,覆盖默认的分面单独计算逻辑:
ggplotly(p) %>% plotly::colorbar( limits = c(20, 100), colors = gradientPalette(length(PROBS) + 1) )
- 临时绕开方案:给固定值的行添加量级极小的随机扰动,例如将代码中
rep(50, 100)替换为rep(50, 100) + rnorm(100, 0, 1e-6),让该行数值不再完全相等,即可触发正常色阶计算。由于扰动幅度远小于数据展示精度,视觉上不会产生可感知的差异,不影响最终展示效果。
内容的提问来源于stack exchange,提问作者Carlos Davila
相关产品推荐
相关产品推荐

