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

ggplot热力图如何合并离散颜色标度仅显示Fair/Unfair两类图例

Shiny公平性指标热力图渲染修复方案

问题说明

  • 需实现公平性判定规则:指标值落在[-0.1, 0.1]区间为Fair类,其余值为Unfair类,两类使用对应固定颜色填充
  • 要求尽可能保留原有分箱breaks设置,最终图例仅展示Fair、Unfair两个分类,不重复展示Unfair条目
  • 当前平均机会差异(Average Odds Difference)指标输出效果如下:
    平均机会差异指标热力图当前效果

原有实现代码

output$fairness_heatmap <- renderPlot({

  # 读取用户选择的指标
  heatmap_data <- NULL
  groups <- NULL
  values <- NULL
  color <- NULL
  if (input$fairness_metric == "Equal Opportunity Difference") {
    heatmap_data <- rw$`Equal Opportunity Difference`
    groups <- cut(round(heatmap_data, 2), breaks = c(-Inf, -0.11, 0.10, Inf))
    values <- c(unfair_color, fair_color, unfair_color)
    color <- ifelse((round(heatmap_data, 2) <= 0.10000) & (round(heatmap_data, 2) >= -0.10000), "black", "white")
  } else if (input$fairness_metric == "Average Odds Difference") {
    heatmap_data <- rw$`Average Odds Difference`
    groups <- cut(round(heatmap_data, 2), breaks = c(-Inf, -0.11, 0.10, Inf))
    values <- c(unfair_color, fair_color, unfair_color)
    color <- ifelse((round(heatmap_data, 2) <= 0.1000) & (round(heatmap_data, 2) >= -0.1000), "black", "white")
  } else if (input$fairness_metric == "Equalized Odds") {
    heatmap_data <- rw$`Equalized Odds`
    groups <- cut(round(heatmap_data, 2), breaks = c(0.0, 0.1, Inf))
    values <- c(fair_color, unfair_color)
    color <- ifelse(round(heatmap_data, 2) <= 0.10000, "black", "white")
  }

  # 绘制热力图
  ggplot(rw,
         aes(x = rw$label_perc,
             y = rw$prot_attr_perc,
             fill = groups)) +
    geom_tile() +
    geom_text(aes(label = round(heatmap_data, 2)),
              color = color,
              size = 4) +
    xlab(label = "Population with Negative Outcome (%)") +
    ylab(label = "Minority Population in Data (%)") +
    ggtitle(paste(input$fairness_metric, "across scenarios (after reweighing)", sep = " ")) +
    scale_x_continuous(expand = c(0, 0),
                       breaks = breaks,
                       labels = labels) +
    scale_y_continuous(expand = c(0, 0),
                       breaks = breaks,
                       labels = rev(labels)) +
    scale_fill_manual("Fairness",
                      breaks = levels(groups),
                      labels = c("Unfair", "Fair", "Unfair"),
                      values = values) +
    theme(
      panel.grid.major.x = element_blank(),
      panel.grid.major.y = element_blank(),
      plot.background = element_blank(),
      rect = element_blank(),
      panel.grid = element_blank()
    )
}, bg = "transparent")

修复方案

完全保留原有分箱breaks设置,仅做3处调整即可实现需求:

  1. 复用原有已验证正确的阈值判断逻辑(即文本颜色color的判定规则),新增二分类公平性字段,避免重复写判断逻辑引入误差
  2. 将热力图填充映射从原始三分箱/二分箱因子改为新增的二分类公平性字段
  3. 调整填充标度参数,仅指定Fair、Unfair两个分类的颜色和标签,自动合并同色分类,同时修正aes中直接用rw$映射列名的不规范写法,避免Shiny响应式更新时出现渲染异常

修复后完整代码:

output$fairness_heatmap <- renderPlot({

  # 读取用户选择的指标
  heatmap_data <- NULL
  groups <- NULL
  color <- NULL
  if (input$fairness_metric == "Equal Opportunity Difference") {
    heatmap_data <- rw$`Equal Opportunity Difference`
    groups <- cut(round(heatmap_data, 2), breaks = c(-Inf, -0.11, 0.10, Inf))
    color <- ifelse((round(heatmap_data, 2) <= 0.10000) & (round(heatmap_data, 2) >= -0.10000), "black", "white")
  } else if (input$fairness_metric == "Average Odds Difference") {
    heatmap_data <- rw$`Average Odds Difference`
    groups <- cut(round(heatmap_data, 2), breaks = c(-Inf, -0.11, 0.10, Inf))
    color <- ifelse((round(heatmap_data, 2) <= 0.1000) & (round(heatmap_data, 2) >= -0.1000), "black", "white")
  } else if (input$fairness_metric == "Equalized Odds") {
    heatmap_data <- rw$`Equalized Odds`
    groups <- cut(round(heatmap_data, 2), breaks = c(0.0, 0.1, Inf))
    color <- ifelse(round(heatmap_data, 2) <= 0.10000, "black", "white")
  }

  # 新增二分类公平性字段,完全复用原有阈值逻辑,无需修改原有分箱breaks
  fair_cat <- ifelse(color == "black", "Fair", "Unfair")

  # 绘制热力图
  ggplot(rw,
         aes(x = label_perc,
             y = prot_attr_perc,
             fill = fair_cat)) +
    geom_tile() +
    geom_text(aes(label = round(heatmap_data, 2)),
              color = color,
              size = 4) +
    xlab(label = "Population with Negative Outcome (%)") +
    ylab(label = "Minority Population in Data (%)") +
    ggtitle(paste(input$fairness_metric, "across scenarios (after reweighing)", sep = " ")) +
    scale_x_continuous(expand = c(0, 0),
                       breaks = breaks,
                       labels = labels) +
    scale_y_continuous(expand = c(0, 0),
                       breaks = breaks,
                       labels = rev(labels)) +
    scale_fill_manual("Fairness",
                      breaks = c("Fair", "Unfair"),
                      values = c("Fair" = fair_color, "Unfair" = unfair_color),
                      labels = c("Fair", "Unfair")) +
    theme(
      panel.grid.major.x = element_blank(),
      panel.grid.major.y = element_blank(),
      plot.background = element_blank(),
      rect = element_blank(),
      panel.grid = element_blank()
    )
}, bg = "transparent")

修复效果说明

  • 原有分箱逻辑完全保留,数值判定和填充色100%匹配规则:[-0.1, 0.1]区间为Fair类用fair_color填充,其余区间为Unfair类用unfair_color填充
  • 图例仅展示Fair、Unfair两个条目,无重复分类
  • 修正了原代码中aes直接调用rw$列名的潜在问题,响应式渲染更稳定

内容的提问来源于stack exchange,提问作者Matthew Francis

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 19:42:14