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

如何在ggplot2条形图中正确排序月-年格式的X轴?

问题:ggplot2条形图坐标轴排序异常

我有一个包含年份(J)、月份(M)、年月组合(Monat,格式为月份-年份)、部门名称(Wer)和月度收入(Einnahmen)的数据框。需要绘制堆叠条形图,以Monat为X轴、Einnahmen为Y轴、Wer作为分类填充变量,但当前X轴的排序不符合实际年月顺序。尝试过将M和J转为因子、使用reorder函数,都没解决问题。另外因为X轴标签密集,用了coord_flip()翻转坐标轴,这也给排序处理带来了麻烦。

相关代码如下:

library(dplyr)
library(ggplot2)

df_cre <- data.frame(J=c(2020, 2020, 2020, 2020, 2020, 2020, 2020, 2020, 
                         2020, 2020, 2020, 2020, 2021, 2021, 2021, 2021, 2021, 2021, 
                         2021, 2021, 2021, 2021, 2021, 2021, 2021, 2021, 2021, 2022, 
                         2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 
                         2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2023, 2023, 
                         2023, 2023, 2023, 2023), 
                     M=c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 
                       11, 12, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 11, 11, 12, 12, 
                       1, 1, 2, 2, 3, 4, 5, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 
                       12, 1, 2, 3, 4, 5, 5), 
                     Wer=c("Abt1", "Abt1", "Abt1", "Abt1", 
                      "Abt1", "Abt1", "Abt1", "Abt1", "Abt1", "Abt1", "Abt1", 
                      "Abt1", "Abt1", "Abt1", "Abt1", "Abt1", "Abt1", "Abt1", 
                      "Abt1", "Abt1", "Abt1", "Abt1", "Abt2", "Abt1", "Abt2", 
                      "Abt1", "Abt2", "Abt1", "Abt2", "Abt1", "Abt2", "Abt1", 
                      "Abt1", "Abt1", "Abt1", "Abt1", "Abt2", "Abt1", "Abt2", 
                      "Abt1", "Abt2", "Abt1", "Abt2", "Abt1", "Abt2", "Abt1", 
                      "Abt1", "Abt1", "Abt1", "Abt1", "Abt1", "Abt2"), 
                     Einnahmen=c(20265.43, 
                       9323.48, 3350.52, 3338.37, 3317.05, 7223.91, 4632.8, 23264.63, 
                       3678.72, 3374.29, 8290, 8176.53, 7805.57, 3276.87, 3490.59, 
                       3189.03, 3189.72, 7115.97, 3183.22, 3182.24, 3475.89, 3343.2, 
                       203.71, 8095.84, 599.64, 3214.26, 639.52, 3567.89, 509.28, 
                       7327.42, 644.01, 3452.29, 3623.8, 3363.84, 7580.19, 3975.35, 
                       1913, 3796.32, 1110, 3765.24, 1110, 3976.99, 1110, 7542.8, 
                       1549, 3529.44, 3451.7, 3476.97, 3495.02, 4110.98, 485.48, 
                       447.02), 
                     Monat=c("1-2020", "2-2020", "3-2020", "4-2020", "5-2020", 
                      "6-2020", "7-2020", "8-2020", "9-2020", "10-2020", "11-2020", 
                      "12-2020", "1-2021", "2-2021", "3-2021", "4-2021", "5-2021", 
                      "6-2021", "7-2021", "8-2021", "9-2021", "10-2021", "10-2021", 
                      "11-2021", "11-2021", "12-2021", "12-2021", "1-2022", "1-2022", 
                      "2-2022", "2-2022", "3-2022", "4-2022", "5-2022", "6-2022", 
                      "7-2022", "7-2022", "8-2022", "8-2022", "9-2022", "9-2022", 
                      "10-2022", "10-2022", "11-2022", "11-2022", "12-2022", "1-2023", 
                      "2-2023", "3-2023", "4-2023", "5-2023", "5-2023"))

df_cre %>% 
  ggplot(aes(fill=Wer, y=Einnahmen, x=Monat)) + 
  geom_bar(position="stack", stat="identity") +
  coord_flip() +
  #scale_x_discrete(breaks = scales::pretty_breaks(n=10)) 
  scale_x_discrete(guide = guide_axis(n.dodge = 2))

当前错误的排序效果:
排序错误的条形图


解决方法

问题根源是Monat列是字符串类型,ggplot默认按字典序排序(比如"1-2021"会排在"10-2020"前面)。以下两种方案可解决排序问题:

方案1:生成有序因子

基于日期排序后,将Monat转为有序因子,保留原显示文本:

library(dplyr)
library(ggplot2)

df_cre <- df_cre %>%
  # 生成日期列用于排序
  mutate(date = as.Date(paste0(J, "-", M, "-01")),
         # 按日期顺序生成有序因子
         Monat_ordered = factor(Monat, levels = unique(Monat[order(date)])))

# 使用有序因子作为x轴绘图
df_cre %>% 
  ggplot(aes(fill=Wer, y=Einnahmen, x=Monat_ordered)) + 
  geom_bar(position="stack", stat="identity") +
  coord_flip() +
  scale_x_discrete(guide = guide_axis(n.dodge = 2)) +
  labs(x = "年月")

方案2:直接使用日期轴

将年月转为日期类型,让ggplot自动按时间排序,同时自定义标签格式:

df_cre <- df_cre %>%
  mutate(date = as.Date(paste0(J, "-", M, "-01")))

df_cre %>% 
  ggplot(aes(fill=Wer, y=Einnahmen, x=date)) + 
  geom_bar(position="stack", stat="identity") +
  coord_flip() +
  # 自定义日期显示为"月份-年份"格式
  scale_x_date(date_labels = "%m-%Y", breaks = "1 month", guide = guide_axis(n.dodge = 2)) +
  labs(x = "年月")

说明

  • 方案1适合需要严格保留原Monat文本的场景,通过有序因子强制指定排序顺序。
  • 方案2更符合时间序列数据的处理逻辑,利用日期类型的天然排序属性,同时灵活自定义显示格式。

内容的提问来源于stack exchange,提问作者Joysn

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 12:17:00