如何在ggplot中排序因子水平?X轴周数排序异常求助
问题:ggplot2绘制时X轴周数(IDWeek)无法按1-52顺序排列
使用R语言ggplot2绘图时,尝试在aes中指定factor(IDWeek, levels = c(1:52)),但X轴周数仍混乱排列。以下是数据集、绘图代码:
winter_fl <- structure(list(IDWeek = c(1, 2, 2, 3, 3, 4, 5, 5, 6, 7, 8, 9, 10, 11, 12, 13, 13, 14, 14, 16, 16, 17, 17, 18, 18, 28, 28, 29, 30, 30, 31, 31, 32, 33, 34, 35, 35, 36, 36, 37, 37, 38, 39, 40, 41, 42, 43, 43, 44, 45, 45, 46, 47, 48, 49, 50, 51, 52), race = c("W", "W", "W", "W", "W", "W", "W", "W", "W", "W", "W", "W", "W", "W", "W", "W", "W", "W", "W", "W", "W", "W", "W", "W", "W", "W", "W", "W", "W", "W", "W", "W", "W", "W", "W", "W", "W", "W", "W", "W", "W", "W", "W", "W", "W", "W", "W", "W", "W", "W", "W", "W", "W", "W", "W", "W", "W", "W"), z = c("Weekly Median FL", "Estimated Fish Passage", "Weekly Median FL", "Estimated Fish Passage", "Weekly Median FL", "Weekly Median FL", "Estimated Fish Passage", "Weekly Median FL", "Weekly Median FL", "Weekly Median FL", "Weekly Median FL", "Weekly Median FL", "Weekly Median FL", "Weekly Median FL", "Weekly Median FL", "Estimated Fish Passage", "Weekly Median FL", "Estimated Fish Passage", "Weekly Median FL", "Estimated Fish Passage", "Weekly Median FL", "Estimated Fish Passage", "Weekly Median FL", "Estimated Fish Passage", "Weekly Median FL", "Estimated Fish Passage", "Weekly Median FL", "Weekly Median FL", "Estimated Fish Passage", "Weekly Median FL", "Estimated Fish Passage", "Weekly Median FL", "Weekly Median FL", "Weekly Median FL", "Weekly Median FL", "Estimated Fish Passage", "Weekly Median FL", "Estimated Fish Passage", "Weekly Median FL", "Estimated Fish Passage", "Weekly Median FL", "Weekly Median FL", "Weekly Median FL", "Weekly Median FL", "Weekly Median FL", "Weekly Median FL", "Estimated Fish Passage", "Weekly Median FL", "Weekly Median FL", "Estimated Fish Passage", "Weekly Median FL", "Weekly Median FL", "Weekly Median FL", "Weekly Median FL", "Weekly Median FL", "Weekly Median FL", "Weekly Median FL", "Weekly Median FL"), ForkLength_Catch = c(156, 1704, 825, 998, 589, 424, 332, 910, 273, 589, 998, 863, 1645, 2769, 739, 112, 1927, 322, 3088, 138, 116, 238, 741, 129, 327, 267, 211, 535, 157, 723, 154, 2868, 4944, 1025, 4932, 4005, 7979, 8016, 10644, 30035, 12230, 11128, 17513, 22107, 32614, 30997, 82256, 27013, 9993, 17056, 30856, 32796, 21939, 25576, 5178, 3686, 1983, 1271 )), class = "data.frame", row.names = c(NA, -58L)) a <- ggplot(data = filter(winter_fl, z == 'Estimated Fish Passage'),aes(x= factor(IDWeek, levels = c(1:52)), y = ForkLength_Catch), fill= z) + geom_bar(stat='summary', fun= sum, show.legend=FALSE, fill= 'lightpink2',color='black') + ylab("Median ForkLength (mm) and Estimated Fish Passage") + xlab("Week") + scale_y_continuous(labels=comma) + scale_x_discrete(breaks=seq(1,52,1)) + geom_boxplot(data = filter(winter_fl, z == 'Weekly Median FL'), aes(x= factor(IDWeek, levels = c(1:52)), y = ForkLength_Catch), width=0.5, fill = 'goldenrod', outlier.colour = 'pink') + facet_wrap(race ~ z, ncol = 1, strip.position ="top", scales="free_y") + theme_bw(base_size = 9) + theme(strip.text=element_text(size=7,margin=margin()), strip.background=element_rect(colour="azure",fill="#f0f0f0")) #+ scale_x_discrete(breaks=seq(1,52,1))
截图显示X轴周数未按1到52的顺序排列。
解决方案
问题原因
- 两个图层分别转换
IDWeek为因子,但分面(facet_wrap)会基于数据中实际存在的周数重新排序,指定的levels = c(1:52)包含数据中不存在的周数(如15、20-27等),ggplot2会自动过滤这些水平,导致排序逻辑失效。 scale_x_discrete(breaks=seq(1,52,1))强制显示所有1-52刻度,缺失周数的空位置会干扰正常排序。
修改步骤
提前在数据集统一转换为有序因子,避免图层重复处理:
# 将IDWeek转换为包含1-52所有水平的有序因子 winter_fl$IDWeek <- factor(winter_fl$IDWeek, levels = 1:52, ordered = TRUE)简化绘图代码,去掉重复的因子转换,按需调整X轴刻度:
library(dplyr) library(ggplot2) library(scales) # 提前处理因子 winter_fl$IDWeek <- factor(winter_fl$IDWeek, levels = 1:52, ordered = TRUE) a <- ggplot(data = filter(winter_fl, z == 'Estimated Fish Passage'), aes(x= IDWeek, y = ForkLength_Catch)) + geom_bar(stat='summary', fun= sum, show.legend=FALSE, fill= 'lightpink2',color='black') + ylab("Median ForkLength (mm) and Estimated Fish Passage") + xlab("Week") + scale_y_continuous(labels=comma) + # 可选:只显示数据中存在的周数作为刻度,避免空刻度 scale_x_discrete(breaks = unique(winter_fl$IDWeek)) + geom_boxplot(data = filter(winter_fl, z == 'Weekly Median FL'), aes(x= IDWeek, y = ForkLength_Catch), width=0.5, fill = 'goldenrod', outlier.colour = 'pink') + facet_wrap(race ~ z, ncol = 1, strip.position ="top", scales="free_y") + theme_bw(base_size = 9) + theme(strip.text=element_text(size=7,margin=margin()), strip.background=element_rect(colour="azure",fill="#f0f0f0")) print(a)若需显示所有1-52刻度,将
scale_x_discrete改为scale_x_discrete(breaks=seq(1,52,1))即可,此时X轴会按1-52顺序排列,缺失周数位置留白。
关键说明
- 提前统一处理因子水平,确保整个数据集的
IDWeek排序一致,分面时不会打乱顺序。 ordered = TRUE明确指定因子的顺序优先级,进一步保障排序正确性。
内容的提问来源于stack exchange,提问作者Salvador
相关产品推荐
相关产品推荐

