ggplot2中geom_hexbin分箱计数与渐变填充颜色映射不准确问题
问题:ggplot2中geom_hex分箱计数与渐变填充映射不准确
我尝试使用ggplot2绘制分箱散点图,基础代码如下:
library(ggplot2) bks = seq(from = 0, to = 10000, by = 1000) d <- ggplot(diamonds, aes(carat, price)) + theme_bw() d + geom_point(alpha = 0.01)
使用geom_hex时,分箱计数与渐变刻度的映射不准确:
d + geom_hex(aes(fill = after_stat(count)), bins = 30, colour = "white") + scale_fill_distiller(palette = "Spectral", breaks = bks) + geom_text(data = diamonds, aes(x = carat, y = price, label = after_stat(count)), stat="binhex", bins=30, show.legend=FALSE, colour="black", size=2.5)
例如计数为5809和5556的分箱仍显示为蓝色。但使用geom_bin_2d时,映射是准确的:
d + geom_bin_2d(aes(fill = after_stat(count)), bins = 30) + scale_fill_distiller(palette = "Spectral", breaks = bks) + geom_text(data = diamonds, aes(x = carat, y = price, label = after_stat(count)), stat="bin_2d", bins=30, show.legend=FALSE, colour="black", size=2.5)
问题原因
- 调色板类型不匹配:
Spectral是发散型调色板,但scale_fill_distiller默认使用type="seq"(顺序型)逻辑解析调色板,导致颜色映射的区间划分错误,高数值分箱无法正确对应到调色板的深色(红色)区域。 - 分箱计算重复的潜在偏差:
geom_hex和geom_text各自独立计算分箱,即使参数相同,也可能因计算细节出现微小差异,导致文本显示的count与六边形填充的count不完全匹配。
解决方法
方法1:正确配置发散型调色板
在scale_fill_distiller中指定type="div",并设置合适的midpoint(通常取count的中位数或均值),让发散型调色板正确映射数值范围:
# 计算分箱count的中位数作为映射中点 count_mid <- median(ggplot2:::binhex(diamonds$carat, diamonds$price, bins=30)$count) d + geom_hex(aes(fill = after_stat(count)), bins = 30, colour = "white") + scale_fill_distiller(palette = "Spectral", breaks = bks, type = "div", midpoint = count_mid) + geom_text(stat="binhex", bins=30, aes(label = after_stat(count)), show.legend=FALSE, colour="black", size=2.5)
方法2:改用顺序型调色板
如果不需要发散型配色,直接使用顺序型调色板(如"Reds"、"Blues"),无需额外配置类型:
d + geom_hex(aes(fill = after_stat(count)), bins = 30, colour = "white") + scale_fill_distiller(palette = "Reds", breaks = bks) + geom_text(stat="binhex", bins=30, aes(label = after_stat(count)), show.legend=FALSE, colour="black", size=2.5)
方法3:预计算分箱数据(彻底避免分箱差异)
先统一计算六边形分箱的结果,再基于该数据绘制图形,确保填充和文本使用完全一致的count值:
# 预计算分箱数据 hex_data <- ggplot_build(d + geom_hex(aes(fill = after_stat(count)), bins=30))$data[[1]] # 绘制图形 d + geom_hex(data = hex_data, aes(x = x, y = y, fill = count), bins = 30, colour = "white") + scale_fill_distiller(palette = "Spectral", breaks = bks, type = "div", midpoint = median(hex_data$count)) + geom_text(data = hex_data, aes(x = x, y = y, label = count), show.legend=FALSE, colour="black", size=2.5)
内容的提问来源于stack exchange,提问作者Crops
相关产品推荐
相关产品推荐

