如何调整ggplot2箱线图的X轴Periode类别顺序?
解决ggplot2箱线图X轴Periode类别乱序问题
问题根源
你的X轴Periode类别是字符型,ggplot默认按字典序排列,因此会出现"Periode 0-14"之后直接跳到"Periode 121-180"的错乱情况。要实现时间先后顺序排列,需将Periode列转换为有序因子(ordered factor),并指定自定义的顺序规则。
解决方案步骤
- 统一定义符合时间逻辑的Periode顺序列表,与你设置列名的顺序保持一致
- 将
vb2、vb4或合并后的vb数据中的Periode列转换为有序因子,绑定自定义顺序作为levels参数 - 绘图时直接使用转换后的因子列,ggplot会自动按指定顺序排列X轴
修改后的完整代码
library(readxl) library(writexl) library(ggplot2) library(car) library(xlsx) library(dplyr) library(tidyr) df1 <- read_excel("C:/Users/seger_rjymtxc/Desktop/Statistiek/Map1.xlsx") df1a <- df1[df1$Voederbeurt == "Voederbeurt 2",] df1b <- df1[df1$Voederbeurt == "Voederbeurt 4",] # Voederbeurt 2 uniekDiernummera <- unique(df1a$Diernummer) print(uniekDiernummera) length(uniekDiernummera) # 14 maxdagen <- 390 df2a <- matrix(0,length(uniekDiernummera),maxdagen) for (j in 1:length(uniekDiernummera)){ dierdata <- which(df1a$Diernummer==uniekDiernummera[j]) for (k in 1:maxdagen){ leeftijdVoor <- df1a$Leeftijd[dierdata[max(which(df1a$Leeftijd[dierdata]<k))]] leeftijdNa <- df1a$Leeftijd[dierdata[min(which(df1a$Leeftijd[dierdata]>=k))]] if (!(is.na(leeftijdNa)|is.na(leeftijdVoor))){ df2a[j,k] <- (df1a$Gewicht[(df1a$Diernummer==uniekDiernummera[j])&(df1a$Leeftijd==leeftijdNa)]- df1a$Gewicht[(df1a$Diernummer==uniekDiernummera[j])&(df1a$Leeftijd==leeftijdVoor)])/(leeftijdNa-leeftijdVoor) } else { df2a[j,k] <- NA } } } rownames(df2a) <- c(uniekDiernummera) matplot(t(df2a),type="l") periode <- rbind(c(1,15,29,43,57,71,121,181,241,301), c(14,28,42,56,70,120,180,240,300,390)) df3a <- matrix(0,nrow(df2a),ncol(periode)) for (i in 1:ncol(periode)){ df3a[,i] <- rowMeans(df2a[,c(periode[1,i]:periode[2,i])],na.rm=TRUE) } rownames(df3a) <- c(uniekDiernummera) matplot(t(df3a),type="l") # 定义Periode的正确时间顺序,后续复用 periode_order <- c("Periode 0-14","Periode 15-28","Periode 29-42","Periode 43-56", "Periode 57-70", "Periode 71-120","Periode 121-180","Periode 181-240","Periode 241-300","Periode 301-390") colnames(df3a) <- periode_order # voederbeurt 4 uniekDiernummerb <- unique(df1b$Diernummer) print(uniekDiernummerb) maxdagen <- 390 df2b <- matrix(0,length(uniekDiernummerb),maxdagen) for (j in 1:length(uniekDiernummerb)){ dierdata <- which(df1b$Diernummer==uniekDiernummerb[j]) for (k in 1:maxdagen){ leeftijdVoor <- df1b$Leeftijd[dierdata[max(which(df1b$Leeftijd[dierdata]<k))]] leeftijdNa <- df1b$Leeftijd[dierdata[min(which(df1b$Leeftijd[dierdata]>=k))]] if (!(is.na(leeftijdNa)|is.na(leeftijdVoor))){ df2b[j,k] <- (df1b$Gewicht[(df1b$Diernummer==uniekDiernummerb[j])&(df1b$Leeftijd==leeftijdNa)]- df1b$Gewicht[(df1b$Diernummer==uniekDiernummerb[j])&(df1b$Leeftijd==leeftijdVoor)])/(leeftijdNa-leeftijdVoor) } else { df2b[j,k] <- NA } } } matplot(t(df2b),type="l") periode <- rbind(c(1,15,29,43,57,71,121,181,241,301), c(14,28,42,56,70,120,180,240,300,390)) df3b <- matrix(0,nrow(df2b),ncol(periode)) for (i in 1:ncol(periode)){ df3b[,i] <- rowMeans(df2b[,c(periode[1,i]:periode[2,i])],na.rm=TRUE) } matplot(t(df3b),type="l") rownames(df2b) <- c(uniekDiernummerb) rownames(df3b) <- c(uniekDiernummerb) colnames(df3b) <- periode_order ## V2 df3a_table=as.data.frame(df3a) df3a_table[,11]=row.names(df3a_table) df3a_table%>%dplyr::select(-c("Periode 301-390"))%>%pivot_longer(cols = all_of(periode_order[-10]), names_to = 'Periode', values_to = 'Waarden') -> vb2 # 将Periode转换为有序因子,绑定自定义顺序 vb2$Periode <- factor(vb2$Periode, levels = periode_order[-10], ordered = TRUE) vb2 %>% group_by(Periode) %>% summarise(min = min(na.exclude(Waarden)), max = max(na.exclude(Waarden)),gem=mean(na.exclude(Waarden)),sdd=sd(na.exclude(Waarden)))->vb_data # 直接使用因子列绘图,无需转字符型 plot=ggplot(vb2,aes(Periode, as.numeric(Waarden))) plot+geom_boxplot() ##V4 df3b_table=as.data.frame(df3b) df3b_table[,11]=row.names(df3b_table) df3b_table%>%dplyr::select(-c("Periode 301-390"))%>%pivot_longer(cols = all_of(periode_order[-10]), names_to = 'Periode', values_to = 'Waarden') -> vb4 # 转换为有序因子 vb4$Periode <- factor(vb4$Periode, levels = periode_order[-10], ordered = TRUE) vb4 %>% group_by(Periode) %>% summarise(min = min(na.exclude(Waarden)), max = max(na.exclude(Waarden)),gem=mean(na.exclude(Waarden)),sdd=sd(na.exclude(Waarden)))->vb4_data plot=ggplot(vb4,aes(Periode, as.numeric(Waarden))) plot+geom_boxplot() # 合并数据并确保因子顺序一致 vb2$voederbeurt="2" vb4$voederbeurt="4" vb=rbind(vb2,vb4) vb$Periode <- factor(vb$Periode, levels = periode_order[-10], ordered = TRUE) plot=ggplot(vb,aes(x=Periode,y=as.numeric(Waarden),fill=voederbeurt)) plot+geom_boxplot()
关键修改点
- 提前定义
periode_order列表,统一管理Periode的时间顺序,避免重复编写 - 在生成
vb2和vb4后,将Periode列转换为有序因子,指定levels为排除最后一项的顺序列表(与你select排除"Periode 301-390"的操作对应) - 绘图时不再使用
as.character(Periode),直接使用转换后的因子列,ggplot会自动按指定顺序排列X轴
内容的提问来源于stack exchange,提问作者Liane Segers
相关产品推荐
相关产品推荐

