R语言ggplot堆叠条形图:堆叠顺序与轴排序冲突问题求解
解决ggplot2堆叠条形图的双排序问题
问题背景
需要绘制堆叠条形图,同时满足两个排序需求:
- 每个堆叠条内的抗生素(
MedicatienaamNieuw)按Frequentie从高到低排序(例如KAA组需按红-蓝-橙顺序) - x轴(经
coord_flip()翻转后为y轴)的Specialisme按-Freq_totaal重新排序
遇到的问题:
- 初始代码能保证轴排序正确,但堆叠顺序是全局频数排序,不符合组内排序要求
- 尝试的循环绘图代码解决了堆叠顺序问题,但
reorder(Specialisme, -Freq_totaal)失效,轴排序错误
数据示例
# 数据结构示例 data.frame( MedicatienaamNieuw = c("augmentin", "cefazoline", "ceftriaxon", "cefuroxim", "clindamicine", "metronidazol"), Specialisme = rep("KAA", 6), Frequentie = c(5, 115, 1, 1, 161, 82), Freq_totaal = rep(365, 6) )
初始代码(轴排序正确,堆叠顺序错误)
ggplot(data = Antibiotica2.1) + aes( x = reorder(Specialisme, -Freq_totaal), y = Frequentie, fill = reorder(MedicatienaamNieuw, +Frequentie)) + geom_bar( stat = "identity", position = "stack") + ggtitle( label = "Antibioticagebruik per specialisme in het AZU", subtitle = "Aantallen uit het jaar 2022") + theme( plot.title = element_text(hjust = 0.5), plot.subtitle = element_text(hjust = 0.5), aspect.ratio = 4/3) + xlab("Specialisme") + ylab("Aantallen") + scale_y_continuous(breaks = seq(0, 1200, 200)) + labs(fill='Antibiotica') + scale_fill_manual(values=c("#984ea3", "#fed9a6", "#ffffb3", "#e5d8bd", "#beaed4", "#e41a1c", "#4daf4a", "#D55E00", "#0072B2")) + coord_flip()
尝试的第二种代码(堆叠顺序正确,轴排序错误)
library(purrr) bars <- map(unique(Antibiotica2.1$Specialisme) , ~geom_bar(stat = "identity", position = "stack" , data = Antibiotica2.1 %>% filter(Specialisme == .x))) Antibiotica2.1 %>% ggplot(aes( x = reorder(Specialisme, -Freq_totaal), y = Frequentie, fill = reorder(MedicatienaamNieuw, +Frequentie))) + bars + theme( plot.title = element_text(hjust = 0.5), plot.subtitle = element_text(hjust = 0.5), aspect.ratio = 4/3) + scale_y_continuous(breaks = seq(0, 1200, 200)) + ggtitle( label = "Antibioticagebruik per specialisme in het AZU", subtitle = "Aantallen uit het jaar 2022") + xlab("Specialisme") + ylab("Aantallen") + labs(fill = 'Antibiotica') + scale_fill_manual(values = c("#984ea3", "Snow 4", "#0072B2", "#e5d8bd", "#beaed4", "#4daf4a", "#e41a1c", "#D55E00", "Yellow")) + coord_flip()
解决方案:预处理数据设置因子水平
核心思路是提前对数据分组排序,手动设置因子水平,避免ggplot全局排序的限制:
1. 数据预处理
library(dplyr) library(ggplot2) # 处理数据,分别设置两个变量的因子水平 Antibiotica_processed <- Antibiotica2.1 %>% # 按Specialisme的总频数降序设置因子水平,保证轴排序正确 mutate(Specialisme = factor(Specialisme, levels = unique(reorder(Specialisme, -Freq_totaal)))) %>% # 按Specialisme分组,每组内按Frequentie降序排列抗生素 group_by(Specialisme) %>% arrange(desc(Frequentie), .by_group = TRUE) %>% # 把MedicatienaamNieuw转成因子,水平为分组排序后的顺序,保证组内堆叠顺序正确 mutate(MedicatienaamNieuw = factor(MedicatienaamNieuw, levels = unique(MedicatienaamNieuw))) %>% ungroup()
2. 绘图代码
ggplot(data = Antibiotica_processed) + aes(x = Specialisme, y = Frequentie, fill = MedicatienaamNieuw) + geom_bar(stat = "identity", position = "stack") + ggtitle( label = "Antibioticagebruik per specialisme in het AZU", subtitle = "Aantallen uit het jaar 2022") + theme( plot.title = element_text(hjust = 0.5), plot.subtitle = element_text(hjust = 0.5), aspect.ratio = 4/3) + xlab("Specialisme") + ylab("Aantallen") + scale_y_continuous(breaks = seq(0, 1200, 200)) + labs(fill='Antibiotica') + scale_fill_manual(values=c("#984ea3", "#fed9a6", "#ffffb3", "#e5d8bd", "#beaed4", "#e41a1c", "#4daf4a", "#D55E00", "#0072B2")) + coord_flip()
方案说明
- 初始代码的
reorder(MedicatienaamNieuw, +Frequentie)是全局排序,会把所有抗生素按整体频数排序,而非每个科室(Specialisme)内的频数排序 - 循环绘图的方法中,每个
geom_bar用的是子集数据,ggplot会默认以第一个子集的Specialisme水平作为轴顺序,导致全局的reorder失效 - 预处理数据设置因子水平的方法,分别控制了轴的排序和每组内堆叠的排序,同时满足两个需求
内容的提问来源于stack exchange,提问作者Yvonne
相关产品推荐
相关产品推荐

