geom_hex与geom_bin_2d分箱绘图结果冲突的原因及标准化方案
关于geom_hex与geom_bin_2d分箱绘图差异的问题与解决方法
我尝试用geom_hex和geom_bin_2d的分箱功能解决绘图过度叠加问题,但两者输出的计数显示差异极大。虽然知道分箱逻辑不同,但想明白差异为何这么显著,以及如何让两者生成可对比的标准化结果,避免解读混乱。
差异显著的核心原因
1. 分箱形状与点归属逻辑完全不同
geom_bin_2d采用轴对齐的正方形网格,每个分箱是严格的矩形,数据点只会落入一个正方形单元,统计逻辑是矩形区域内的点计数。geom_hex采用交错排列的六边形网格,相邻行的六边形偏移半个边长,点的归属是基于六边形的覆盖区域,和正方形分箱的统计单元完全不重合,同一组点在两种规则下的计数自然差异明显。
2. bins参数的定义不一致
- 对
geom_bin_2d,bins是x轴和y轴各自的分箱数量,比如bins=40意味着x轴40个分箱、y轴40个分箱,总共有1600个正方形单元。 - 对
geom_hex,bins仅指x轴方向的六边形数量,y轴的六边形数量会根据坐标轴比例自动调整,总单元数更少,且每个六边形的面积和正方形分箱的面积不相等,统计粒度不一致进一步放大了计数差异。
标准化绘图结果的方法
1. 用binwidth替代bins统一统计粒度
不要依赖模糊的bins参数,直接用binwidth指定分箱的实际尺寸:
- 对
geom_bin_2d,用binwidth=c(x_width, y_width)定义正方形的宽和高。 - 对
geom_hex,为了让六边形面积和正方形分箱接近,设置binwidth=c(x_width, y_width * sqrt(3)/2)(六边形垂直高度与水平宽度的比例为√3/2≈0.866)。
2. 强制统一颜色标尺
确保两者使用完全相同的填充色设置:包括limits(计数范围)、breaks(刻度断点)、palette(颜色方案),这样颜色对应的计数区间完全一致,避免视觉上的误导。
3. 可选:手动对齐分箱原点
geom_bin_2d可通过origin参数指定分箱起始点;geom_hex虽无直接参数,但可通过偏移数据坐标让六边形网格与正方形网格对齐,此操作仅在需要严格对齐统计单元时使用。
示例验证
示例1:钻石数据集对比
library(ggplot2) # 定义统一的颜色标尺 bks = seq(from = 0, to = 10000, by = 1000) fill_scale <- scale_fill_distiller(palette = "Spectral", breaks = bks, limits = c(0, 6000)) d <- ggplot(diamonds, aes(carat, price)) # 基础散点图 d + geom_point(alpha = 0.01)

# 用统一binwidth绘制对比图 bw <- c(0.1, 500) # geom_bin_2d版本 d + geom_bin_2d(binwidth = bw) + fill_scale # geom_hex版本(匹配面积) d + geom_hex(binwidth = c(bw[1], bw[2] * sqrt(3)/2)) + fill_scale


示例2:物种分布数据集对比
library(sf) library(ggplot2) library(rgbif) library(maps) # 获取GBIF物种数据 gdata <- occ_data(scientificName = "Aix sponsa", country = "US", year="2020", limit = 5000) gdata <- gdata$data # 准备美国地图 usa <- sf::st_as_sf(map('usa', plot = FALSE, fill = TRUE)) usa <- sf::st_transform(usa, sp::CRS("+init=epsg:4326")) # 转换物种数据为SF格式 gdata_sf <- st_as_sf(gdata, coords = c('decimalLongitude', 'decimalLatitude'), crs = st_crs(usa)) # 基础散点图 ggplot(usa) + geom_sf() + geom_sf(data = gdata_sf, alpha = 0.1)

# 统一颜色标尺和分箱参数 bks = seq(from = 0, to = 200, by = 50) fill_scale <- scale_fill_distiller(palette = "Spectral", limits = c(0, 200), breaks = bks) bw <- c(0.5, 0.5) # geom_bin_2d绘图 ggplot(usa) + geom_sf() + geom_bin_2d(data = gdata, aes(x = decimalLongitude, y = decimalLatitude, fill = after_stat(count)), alpha = 0.8, colour = "white", binwidth = bw) + fill_scale + geom_sf(data = gdata_sf, alpha = 0.1) + theme_void() # geom_hex绘图(匹配面积) ggplot(usa) + geom_sf() + geom_hex(data = gdata, aes(x = decimalLongitude, y = decimalLatitude, fill = after_stat(count)), alpha = 0.8, colour = "white", binwidth = c(bw[1], bw[2] * sqrt(3)/2)) + fill_scale + geom_sf(data = gdata_sf, alpha = 0.1) + theme_void()

内容的提问来源于stack exchange,提问作者Crops
相关产品推荐
相关产品推荐

