You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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原生输出效果:
    ggplot原生输出效果
  • ggplotly异常输出效果:
    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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 11:48:17