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

如何调整ggplot2箱线图的X轴Periode类别顺序?

解决ggplot2箱线图X轴Periode类别乱序问题

问题根源

你的X轴Periode类别是字符型,ggplot默认按字典序排列,因此会出现"Periode 0-14"之后直接跳到"Periode 121-180"的错乱情况。要实现时间先后顺序排列,需将Periode列转换为有序因子(ordered factor),并指定自定义的顺序规则。

解决方案步骤

  1. 统一定义符合时间逻辑的Periode顺序列表,与你设置列名的顺序保持一致
  2. 将vb2、vb4或合并后的vb数据中的Periode列转换为有序因子,绑定自定义顺序作为levels参数
  3. 绘图时直接使用转换后的因子列,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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 12:45:35