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

如何在R的Plotly热力图中用colorscale指定缺失数据颜色

Plotly热力图NA值灰色显示优化方案

需求与问题

使用R的plotly绘制热力图时,需要实现:

  • 缺失值(NA)单元格显示为灰色
  • 所有有效数据(含负数)使用自定义配色板
    当前通过替换NA为极小值+设置colorscale的方式,导致最小有效数据也被显示为灰色,需修复该问题。

可复现代码

library(tidyverse)
library(plotly)

df <- structure(list(pop1 = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 2L, 
2L, 2L, 2L, 2L, 3L, 3L, 3L, 3L, 4L, 4L, 4L, 5L, 5L, 6L), levels = c("MCap-KUR", 
"MCap-LAY", "MCap-LIS", "MCap-MAR", "MCap-MAU", "MCap-ORG", "MCap-PH"
), class = "factor"), pop2 = structure(c(6L, 5L, 4L, 3L, 2L, 
1L, 5L, 4L, 3L, 2L, 1L, 4L, 3L, 2L, 1L, 3L, 2L, 1L, 2L, 1L, 1L
), levels = c("MCap-PH", "MCap-ORG", "MCap-MAU", "MCap-MAR", 
"MCap-LIS", "MCap-LAY", "MCap-KUR"), class = "factor"), val = c(0.0595442225256261, 
0.0321423361492723, NA, 0.0350934030053142, 0.0345727091303639, 
0.0721309262141394, 0.00633228225335393, NA, 0.0267124927202649, 
0.0148571426201043, 0.0414373761542232, NA, 0.0178640375765284, 
NA, 0.0208313289311733, NA, NA, NA, 0.0150516521752213, 0.0762165451237571, 
0.0521814425563684)), row.names = c(NA, -21L), class = c("tbl_df", 
"tbl", "data.frame"))

colorscale <- list(
  list(0, "darkgrey"),
  list(1e-05, "darkgrey"),
  list(1e-05,  "#000004FF"),
  list(0.1, "#170C3AFF"),
  list(0.2, "#420A68FF"), 
  list(0.3, "#6B186EFF"),
  list(0.4, "#932667FF"),
  list(0.5,  "#BB3754FF"),
  list(0.6, "#DD513AFF"),
  list(0.7, "#F3771AFF"), 
  list(0.8, "#FCA50AFF"),
  list(0.9, "#F6D645FF"),
  list(1, "#FCFFA4FF")
)

df <- df %>% 
  mutate(
    newval = replace_na(val, min(val, na.rm = T)*1e-5),
    disp = as.character(val)
  ) 

df %>%
  plot_ly() %>%
  add_trace(
    type = "heatmap",
    x = ~pop1,
    y = ~pop2,
    z = ~newval,
    zmin = ~min(val, na.rm = TRUE),
    zmax = ~max(val, na.rm = TRUE),
    colorscale = colorscale,
    customdata = ~disp,
    hovertemplate = "%{customdata}"
  )

最优解决方案:原生参数na.color

Plotly热力图原生支持na.color参数,无需修改NA值,直接指定缺失值的颜色,是最简洁且可靠的方案:

代码实现

# 计算有效数据的极值
data_min <- min(df$val, na.rm = TRUE)
data_max <- max(df$val, na.rm = TRUE)

# 直接使用原始数据绘制
df %>%
  plot_ly() %>%
  add_trace(
    type = "heatmap",
    x = ~pop1,
    y = ~pop2,
    z = ~val,  # 保留原始NA值
    zmin = data_min,
    zmax = data_max,
    # 自定义配色板(示例为inferno色系)
    colorscale = list(
      list(0, "#000004FF"),
      list(0.1, "#170C3AFF"),
      list(0.2, "#420A68FF"), 
      list(0.3, "#6B186EFF"),
      list(0.4, "#932667FF"),
      list(0.5, "#BB3754FF"),
      list(0.6, "#DD513AFF"),
      list(0.7, "#F3771AFF"), 
      list(0.8, "#FCA50AFF"),
      list(0.9, "#F6D645FF"),
      list(1, "#FCFFA4FF")
    ),
    na.color = "darkgrey",  # 直接设置NA值的显示颜色
    customdata = ~as.character(val),
    hovertemplate = "%{customdata}"
  )

方案优势

  1. 无需修改原始数据:保留NA值,逻辑更清晰
  2. 完美兼容正负数据:有效数据完全映射到自定义配色区间,最小有效值不会被误标为灰色
  3. 代码简洁高效:利用原生参数,避免复杂的数值替换和colorscale计算

替代方案:自定义数值映射(兼容旧版Plotly)

如果使用的Plotly版本不支持na.color,可通过将NA映射到有效数据范围外的数值实现:

# 计算有效数据极值
data_min <- min(df$val, na.rm = TRUE)
data_max <- max(df$val, na.rm = TRUE)
# 设置NA映射值:远小于有效数据最小值(兼容负数)
na_val <- data_min - abs(data_min) * 10

# 调整colorscale:将NA值区间设为灰色,有效数据区间用自定义配色
colorscale <- list(
  list(0, "darkgrey"),
  list((na_val - data_min)/(data_max - data_min), "darkgrey"),
  list((na_val - data_min)/(data_max - data_min), "#000004FF"),
  list(0.1, "#170C3AFF"),
  list(0.2, "#420A68FF"), 
  list(0.3, "#6B186EFF"),
  list(0.4, "#932667FF"),
  list(0.5, "#BB3754FF"),
  list(0.6, "#DD513AFF"),
  list(0.7, "#F3771AFF"), 
  list(0.8, "#FCA50AFF"),
  list(0.9, "#F6D645FF"),
  list(1, "#FCFFA4FF")
)

# 替换NA并绘图
df <- df %>% 
  mutate(
    newval = replace_na(val, na_val),
    disp = as.character(val)
  )

df %>%
  plot_ly() %>%
  add_trace(
    type = "heatmap",
    x = ~pop1,
    y = ~pop2,
    z = ~newval,
    zmin = data_min,
    zmax = data_max,
    colorscale = colorscale,
    customdata = ~disp,
    hovertemplate = "%{customdata}"
  )

内容的提问来源于stack exchange,提问作者Luther Blissett

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.12 14:52:32