R语言ggplot2双Y轴 按x轴匹配合并箱线图与柱状图
R ggplot2 双Y轴合并箱线图与柱状图实现
核心要解决两个问题:一是两个数据集的x轴分类文本、顺序必须完全统一才能对齐;二是次轴数据需要按主轴范围线性缩放,才能在ggplot2的双轴体系下正常展示。
1. 数据预处理(解决x轴错位问题)
提供的两个数据里,「DRK秘书处专业咨询反馈」类别的name文本不一致,必须先统一文本,再固定因子顺序,避免自动排序错位:
library(ggplot2) library(dplyr) library(viridis) # 载入原始数据 F3a <- structure(list(name = c("Newsletter", "Blog", "Rückmeldungen zu \nfachlichen Anfragen beim\n DRK-Generalsekretariat", "Fortbildungen", "Treffen der \n Landesreferent:innen", "Newsletter", "Blog", "Rückmeldungen zu \nfachlichen Anfragen beim\n DRK-Generalsekretariat", "Treffen der \n Landesreferent:innen", "Newsletter", "Blog", "Rückmeldungen zu \nfachlichen Anfragen beim\n DRK-Generalsekretariat", "Fortbildungen", "Treffen der \n Landesreferent:innen", "Newsletter", "Blog", "Rückmeldungen zu \nfachlichen Anfragen beim\n DRK-Generalsekretariat", "Fortbildungen", "Treffen der \n Landesreferent:innen", "Newsletter", "Blog", "Rückmeldungen zu \nfachlichen Anfragen beim\n DRK-Generalsekretariat", "Fortbildungen", "Treffen der \n Landesreferent:innen", "Newsletter", "Blog", "Rückmeldungen zu \nfachlichen Anfragen beim\n DRK-Generalsekretariat", "Fortbildungen", "Treffen der \n Landesreferent:innen", "Newsletter", "Blog", "Rückmeldungen zu \nfachlichen Anfragen beim\n DRK-Generalsekretariat", "Fortbildungen", "Treffen der \n Landesreferent:innen", "Fortbildungen", "Newsletter", "Fortbildungen", "Newsletter", "Blog", "Rückmeldungen zu \nfachlichen Anfragen beim\n DRK-Generalsekretariat", "Fortbildungen", "Treffen der \n Landesreferent:innen", "Newsletter", "Blog", "Fortbildungen", "Treffen der \n Landesreferent:innen" ), value = c(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 2, 1, 2, 1, 2, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 2, 1, 3, 1, 1, 1, 1, 1, 2, 2, 2, 2, 1, 2, 1, 1)), row.names = c(NA, -46L), class = c("tbl_df", "tbl", "data.frame")) F1a <- structure(list(name = structure(c(1L, 4L, 2L, 3L, 5L), .Label = c("Blog", "Fortbildungen", "Newsletter", "Fachliche Anfragen beim \n DRK-Generalsekretariat", "Treffen der \n Landesreferent:innen"), class = "factor"), value = c(1, 1, 1, 1, 1), n = c(9L, 8L, 9L, 10L, 9L), percent = c(18.8, 16.7, 18.8, 20.8, 18.8)), row.names = c(NA, -5L), class = c("tbl_df", "tbl", "data.frame")) # 统一分类名称 F1a <- F1a %>% mutate(name = recode(name, "Fachliche Anfragen beim \n DRK-Generalsekretariat" = "Rückmeldungen zu \nfachlichen Anfragen beim\n DRK-Generalsekretariat")) # 固定x轴分类顺序 x_levels <- c("Blog", "Fortbildungen", "Newsletter", "Rückmeldungen zu \nfachlichen Anfragen beim\n DRK-Generalsekretariat", "Treffen der \n Landesreferent:innen") F3a$name <- factor(F3a$name, levels = x_levels) F1a$name <- factor(F1a$name, levels = x_levels)
2. 双轴缩放逻辑
ggplot2原生不支持独立范围的双Y轴,次轴数据必须和主轴做线性映射:
- 主轴(左侧)为反向满意度,范围固定为
1(顶部,最满意)~5(底部,最不满意) - 次轴(右侧)为百分比,范围
0~25% - 缩放公式:百分比值映射到主轴的位置为
1 + percent/25*4,次轴标签反向转换即可匹配对应刻度
3. 组合绘图代码
注意调整图层宽度、透明度,避免两个图层互相遮挡:
ggplot() + # 先绘制次轴柱状图,低透明度、大宽度作为背景层 geom_col(data = F1a, aes(x = name, y = 1 + percent/25*4, fill = name), alpha = 0.3, width = 0.6) + # 再绘制主轴箱线图,小宽度、高透明度放在上层 geom_boxplot(data = F3a, aes(x = name, y = value, fill = name), alpha = 0.7, width = 0.3) + # 叠加箱线图上的点层 geom_dotplot(data = F3a, aes(x = name, y = value), binaxis = "y", stackdir = "center", position = "dodge", dotsize = 0.5) + # 配置双Y轴 scale_y_continuous( trans = "reverse", breaks = c(1,2,3,4,5), limits = c(5,1), name = "Zufriedenheit", sec.axis = sec_axis(~ (. -1)/4*25, name = "Prozent", breaks = c(0,5,10,15,20,25)) ) + # 统一viridis离散配色 scale_fill_viridis_d() + # 主题配置 theme_bw() + theme( legend.position = "bottom", legend.title = element_text(size=8), legend.text=element_text(size=8), axis.title.x = element_blank(), # 要和原箱线图一样隐藏x轴的话,把下面两行替换成axis.text.x=element_blank(),axis.ticks.x=element_blank() axis.text.x = element_text(angle = 45, hjust = 1, size = 8), axis.ticks.x = element_line() ) + guides(fill=guide_legend(nrow=4,byrow=TRUE)) + labs(fill = "")
内容的提问来源于stack exchange,提问作者KC15
相关产品推荐
相关产品推荐

