在ggplot2中为分箱轴添加反向对数变换的技术问题
解决ggplot2绘图的轴约束问题
需求说明
- x轴:反向对数刻度,必须显示0刻度
- y轴:分箱轴,需满足
- 分箱按反向顺序展示
- 分箱大小采用对数比例(如0-10的分箱宽度大于10-20)
- x、y轴均需显示0刻度
示例数据
set.seed(123) dat <- data.frame( a = sample(seq(0, 100), 1e4, replace = TRUE), b = sample(1e6, 1e4), t = sample(letters[seq(2)], 1e4, replace = TRUE) )
现有代码的问题
现有实现无法满足全部需求,遗留问题:
- x轴无法显示0刻度:对数刻度下设置
limits=c(0, ...)会报错,尝试scales::pseudo_log_trans或ggallin::pseudolog10_trans无法与反向变换结合 - y轴无法实现对数分箱:
scale_y_binned仅支持等距分箱,对数变换仅适用于连续轴 - y轴无法反向:ggplot2的轴反向变换仅支持连续轴,分箱轴不兼容
解决方案代码
library(ggplot2) library(scales) library(ggthemes) # 自定义x轴的伪对数+反向复合变换 reverse_pseudo_log_trans <- function(sigma = 0.1) { trans <- pseudo_log_trans(sigma = sigma) trans_new( name = "reverse_pseudo_log", transform = function(x) -trans$transform(x), inverse = function(x) trans$inverse(-x), breaks = function(x) { # 生成包含0的breaks,结合对数刻度的常见值 c(0, trans$breaks(x)) |> unique() |> sort(decreasing = TRUE) }, domain = c(0, Inf) ) } # 手动创建y轴的对数分箱并反向排序 # 定义对数间距的分箱断点(包含0) y_breaks <- c(0, 1, 2, 5, 10, 20, 50, 100) # 对a变量做分箱,转为因子并反向排序 dat$a_binned <- cut( dat$a, breaks = y_breaks, include.lowest = TRUE, labels = paste0(y_breaks[-length(y_breaks)], "-", y_breaks[-1]) ) dat$a_binned <- factor(dat$a_binned, levels = rev(levels(dat$a_binned))) # 绘制图形 ggplot(dat, aes(y = a_binned, x = b, colour = t)) + geom_jitter(size = 0.8, alpha = 0.6) + # 应用自定义x轴变换 scale_x_continuous( trans = reverse_pseudo_log_trans(sigma = 0.1), breaks = c(0, 2.5e0, 5e0, 1e1, 2.5e1, 5e1, 1e2, 2.5e2, 5e2, 1e3, 2.5e3, 5e3, 1e4, 2.5e4, 5e4, 1e5, 2.5e5, 5e5, 1e6), expand = c(0, 0), limits = c(0, 1e6) ) + # y轴用离散轴模拟分箱轴 scale_y_discrete( expand = c(0, 0) ) + theme_clean() + theme( axis.text.y = element_text(hjust = 0), axis.ticks.y = element_line() ) + labs(y = "a (对数分箱)", x = "b (反向伪对数刻度)")
关键说明
- x轴处理:通过自定义变换结合伪对数(兼容0值)和反向变换,手动指定包含0的breaks,既保留反向对数的视觉效果,又解决了0刻度无法显示的问题。
- y轴处理:手动生成对数间距的分箱断点,用
cut创建分箱后转为反向排序的因子,用离散轴模拟分箱轴,完美实现反向显示+对数比例分箱的需求。 - 两个轴都通过
expand=c(0,0)和手动设置limits确保0刻度正常显示。
内容的提问来源于stack exchange,提问作者Vongo
相关产品推荐
相关产品推荐

