You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 20:11:10