使用cowplot的plot_grid实现对数Y轴ggplot图固定Y轴范围
解决cowplot组合对数Y轴散点图的Y轴范围统一问题
问题场景
要通过cowplot::plot_grid组合两张散点图,需求如下:
- 两张图均使用对数Y轴(负数值会被自动过滤)
- 两张图的Y轴范围完全对齐,达到
facet_wrap(scales="fixed")的效果 - 两张图的X轴需要设置不同的标签和刻度格式(比如给A的刻度加$符号,给B的加%符号),因此无法使用
facet_wrap
此前尝试通过layer_scales获取图层范围后设置ylim,结果不符合预期,核心原因是对数轴的范围处理逻辑和线性轴不同。
可行方案
1. 先计算全局有效Y值范围
因为对数轴不支持负数,scale_y_log10会自动过滤负的Y值,所以需要从两张图的原始数据中,提取所有正Y值,计算它们的全局最小值和最大值,作为统一的Y轴范围。
2. 通过scale_y_log10(limits = ...)设置统一范围
不要使用ylim(),因为ylim是针对原始数据的线性范围,而scale_y_log10的limits参数是专门适配对数轴的范围设置,能保证轴的显示逻辑正确。
完整代码示例
library(tidyverse) library(cowplot) # 生成示例数据 data_a <- tibble(x = rnorm(100), y = rnorm(100), type = "A") data_b <- tibble(x = rnorm(100, mean = 10), y = rnorm(100, mean = 10), type = "B") # 计算全局有效Y值范围(仅保留正数值) global_y_lims <- c( min(c(data_a$y[data_a$y > 0], data_b$y[data_b$y > 0])), max(c(data_a$y[data_a$y > 0], data_b$y[data_b$y > 0])) ) # 绘制图A:自定义X轴格式 + 统一对数Y轴范围 plot_a <- data_a %>% ggplot(aes(y = y, x = x)) + geom_point() + scale_y_log10(limits = global_y_lims) + scale_x_continuous(labels = ~paste0("$", .x)) # X轴刻度添加$符号 # 绘制图B:自定义X轴格式 + 统一对数Y轴范围 plot_b <- data_b %>% ggplot(aes(y = y, x = x)) + geom_point() + scale_y_log10(limits = global_y_lims) + scale_x_continuous(labels = ~paste0(.x, "%")) # X轴刻度添加%符号 # 组合两张图 plot_grid(plot_a, plot_b)
原方法失效的原因
layer_scales(a)$y$range$range获取的是图层经过对数转换后的轴范围,直接用这个值设置ylim会破坏对数轴的显示逻辑,因为ylim是基于原始数据的线性范围,而非对数转换后的轴刻度范围。- 只有从原始数据中提取未被过滤的正Y值,计算全局范围后,通过
scale_y_log10的limits参数设置,才能保证两张图的对数Y轴范围完全一致。
内容的提问来源于stack exchange,提问作者Moritz Schwarz
相关产品推荐
相关产品推荐

