在R的facet_wrap分面中设置双Y轴,使各面板累计值对应100%
解决分面堆叠面积图次Y轴统一对应100%的问题
问题根源&解决方向
你现在的问题是用了全局固定的转换系数(high组的165),但low组的累计最大值是132,导致两个分面的次Y轴比例不匹配。核心就是不能用同一个转换系数,得按nitrogen分组单独处理,下面给两种实用方案:
方案1:先把数据转成百分比(推荐)
直接在预处理阶段,按high/low分组,把每个x对应的累计值转换成该组x=50时最大值的百分比,这样绘图时根本不用搞次Y轴,每个分面x=50的位置自然就是100%。
代码示例
假设你的dataA有x、nitrogen、堆叠分组(比如叫group)、value这几个字段,按下面步骤处理:
library(dplyr) library(ggplot2) # 第一步:算出每个nitrogen组x=50时的累计最大值 max_vals <- dataA %>% group_by(nitrogen) %>% filter(x == 50) %>% summarise(total_max = sum(value)) %>% ungroup() # 第二步:把最大值合并回原数据,计算每个点的百分比 dataA_percent <- dataA %>% left_join(max_vals, by = "nitrogen") %>% group_by(nitrogen, x) %>% mutate(cum_value = cumsum(value), percent = cum_value / total_max * 100) %>% ungroup() # 第三步:画图,分面即可 ggplot(dataA_percent, aes(x = x, y = percent, fill = group)) + geom_area(position = "stack") + facet_wrap(~nitrogen) + labs(y = "累计百分比(%)")
这个方法最简单,完全不用纠结次Y轴的转换问题,结果也精准。
方案2:保留原始值,给每个分面单独设次Y轴
如果必须保留原始累计值的主Y轴,同时显示百分比次Y轴,可以用ggh4x包的分面自定义刻度功能,给high和low组分别设置对应的转换系数。
代码示例
library(ggplot2) library(ggh4x) # 先算出每个组的转换系数(即x=50时的累计最大值) conv_coeff <- dataA %>% group_by(nitrogen) %>% filter(x == 50) %>% summarise(scale = sum(value)) %>% deframe() # 绘图,给每个分面单独配置次Y轴 ggplot(dataA, aes(x = x, y = cumsum(value), fill = group)) + geom_area(position = "stack") + facet_wrap(~nitrogen) + # 主Y轴显示原始累计值 scale_y_continuous(name = "累计值") + # 用ggh4x给每个分面单独设置次Y轴转换规则 facetted_pos_scales(y = list( nitrogen == "high" ~ scale_y_continuous( sec.axis = sec_axis(~./165, name = "累计百分比(%)", breaks = c(0, 0.5, 1), labels = c("0%", "50%", "100%")) ), nitrogen == "low" ~ scale_y_continuous( sec.axis = sec_axis(~./132, name = "累计百分比(%)", breaks = c(0, 0.5, 1), labels = c("0%", "50%", "100%")) ) ))
这里通过facetted_pos_scales让high组用165做分母、low组用132做分母,两个分面的次Y轴在x=50处都会精准对应100%。
内容的提问来源于stack exchange,提问作者J.K Kim
相关产品推荐
相关产品推荐

