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

ggplot直方图着色异常排查:零值柱子出现双色问题

问题分析与解决

问题重现

你使用以下数据集df4和ggplot代码绘制直方图,希望将负数对应的柱子设为蓝色(#41A2D0),非负数(含0)设为灰色,但零值柱子出现了双色异常:

数据集:

df4<- data.frame(structure(list(Percentage.of.change = c(0.8, 0.6, -0.6, -3.1, 
2.7, -1.4, -3.4, -11.3, -3.8, -6.8, 5, 0.6, -2.7, -2.4, -0.9, 
-2.8, -3.5, 1.2, 4.7, -2.5, -4, -2.9, 0, -2.2, -0.9, -4.1, 0, 
-1.9, -5.2, -6.4, -3.9, -2.5, -3.8, -4.5, -1.8, -3.1, -2.7, -9.2, 
-1.9, -5.9, -6.5, -2.3, 0, -3.8, -4.2, -1.5, 1.7, 0, -0.6, -5.3, 
-0.2)), row.names = c(NA, 51L), class = "data.frame")

绘图代码:

ggplot(df4, aes(x = Percentage.of.change,  fill = ifelse(df4$Percentage.of.change < 0, "#41A2D0", "grey"), color = "black")) +
  geom_histogram(binwidth = 1, col="black")+
  scale_fill_manual(values = c( "#41A2D0", "grey"), guide = FALSE) +
  #scale_x_continuous(limits = c(-16,6), breaks = seq(-16,6,1))+
  theme_minimal()+
  labs(x = "Change in Percentage of Body Weight (%)",
       y = "Number of Individuals",
       title = "Relative Weight Change",
       subtitle = "Relative weight change for individuals whose goal was to lose weight and completed the program (n=209)")

问题根源

你之前的代码是给每个数据点单独分配填充色,而非给整个直方图柱子(bin)分配颜色。当某个bin里同时存在正负数据点时,柱子就会被拆分成两种颜色显示。

小数据量时没出现问题,是因为刚好没有正负数据点被分到同一个bin里;数据量变大后,概率升高,就会暴露这个逻辑漏洞。binwidth=1只是设置每个bin的宽度,和颜色异常无关。

解决方法

方法1:用after_stat给bin分配颜色(推荐)

利用ggplot的after_stat函数,在直方图计算完bin之后,根据bin的中心值(或左边界)判断颜色,确保每个bin只有单一颜色:

ggplot(df4, aes(x = Percentage.of.change)) +
  geom_histogram(
    binwidth = 1, 
    col = "black",
    # 根据bin的中心值判断:中心<0设蓝色,否则灰色
    aes(fill = after_stat(x < 0))
  ) +
  scale_fill_manual(
    values = c("FALSE" = "grey", "TRUE" = "#41A2D0"),
    guide = FALSE
  ) +
  theme_minimal() +
  labs(
    x = "Change in Percentage of Body Weight (%)",
    y = "Number of Individuals",
    title = "Relative Weight Change",
    subtitle = "Relative weight change for individuals whose goal was to lose weight and completed the program (n=209)"
  )

如果想更精准控制,可以把after_stat(x < 0)改成after_stat(xmin < 0),用bin的左边界判断,确保所有负数区间的bin都显示蓝色。

方法2:手动计算bin统计量,用geom_col绘制

先手动计算每个bin的计数和区间,再指定颜色,完全掌控绘制逻辑:

library(dplyr)

# 计算每个bin的计数和颜色
bin_data <- df4 %>%
  # 划分左闭右开的bin,和ggplot默认逻辑一致
  mutate(bin = cut(Percentage.of.change, 
                   breaks = seq(floor(min(Percentage.of.change)), 
                                ceiling(max(Percentage.of.change)), 
                                by = 1),
                   include.lowest = TRUE,
                   right = FALSE)) %>%
  count(bin) %>%
  # 计算bin的中心值,用于x轴定位
  mutate(bin_center = as.numeric(sub("\\[(.*),.*)", "\\1", bin)) + 0.5,
         # 根据中心值判断颜色
         fill_color = ifelse(bin_center < 0, "#41A2D0", "grey"))

# 绘制柱状图
ggplot(bin_data, aes(x = bin_center, y = n, fill = fill_color)) +
  geom_col(width = 1, col = "black") +
  scale_fill_identity(guide = FALSE) +
  theme_minimal() +
  labs(
    x = "Change in Percentage of Body Weight (%)",
    y = "Number of Individuals",
    title = "Relative Weight Change",
    subtitle = "Relative weight change for individuals whose goal was to lose weight and completed the program (n=209)"
  )

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 17:28:12