如何用ggplot2将时间序列多变量箱线图整合到同一画布?
问题描述
我有一个名为validation.xlsx的Excel文件,包含132行时间序列数据,涉及time、observed(观测流量)、simulated(模拟流量)三个变量。目前已成功生成两个变量的单独箱线图,但无法将二者整合到同一画布中,寻求解决方案。
数据样例(前6行)
原始数据(df)
| time | observed | simulated |
|---|---|---|
| 2011-01-01 00:00:00 | 40.3 | 24.8 |
| 2011-02-01 00:00:00 | 17.6 | 19.8 |
| 2011-03-01 00:00:00 | 63.9 | 17.2 |
| 2011-04-01 00:00:00 | 114.0 | 75.5 |
| 2011-05-01 00:00:00 | 266.0 | 269.0 |
| 2011-06-01 00:00:00 | 120.0 | 87.2 |
季节分类后数据(seasons)
| time | observed | simulated | season | Time1 | Month | Year | Season |
|---|---|---|---|---|---|---|---|
| 2011-01-01 | 40.3 | 24.8 | Winter | 2011-01-01 | 01 | 2011 | Winter |
| 2011-02-01 | 17.6 | 19.8 | Winter | 2011-02-01 | 02 | 2011 | Winter |
| 2011-03-01 | 63.9 | 17.2 | Winter | 2011-03-01 | 03 | 2011 | Spring |
| 2011-04-01 | 114.0 | 75.5 | Winter | 2011-04-01 | 04 | 2011 | Spring |
| 2011-05-01 | 266.0 | 269.0 | Winter | 2011-05-01 | 05 | 2011 | Spring |
| 2011-06-01 | 120.0 | 87.2 | Winter | 2011-06-01 | 06 | 2011 | Summer |
解决方案
提供两种常用整合方式,根据需求选择:
方式1:合并为同一坐标轴的分组箱线图(直接对比分布)
将宽格式数据转为长格式,用一个变量区分观测/模拟数据,实现同图分组展示:
# 加载依赖包 library(ggplot2) library(tidyverse) library(readxl) # 读取并预处理数据 df <- read_excel("validation.xlsx") df$time <- as.Date(df$time) # 生成月份和季节列(修复原代码中Month生成逻辑) seasons <- df %>% mutate(Month = format(time, "%m"), Season = case_when( Month %in% c("12", "01", "02") ~ "Winter", Month %in% c("03", "04", "05") ~ "Spring", Month %in% c("06", "07", "08") ~ "Summer", Month %in% c("09", "10", "11") ~ "Fall" )) # 转换为长格式数据 long_seasons <- seasons %>% pivot_longer( cols = c(observed, simulated), names_to = "Data_Type", values_to = "Streamflow" ) # 绘制分组箱线图 combined_boxplot <- ggplot(long_seasons, aes(x = Month, y = Streamflow, fill = Data_Type)) + geom_boxplot(alpha = 0.5, position = position_dodge(width = 0.8)) + # 分组错开避免重叠 labs( x = "月份", y = expression(paste("流量, ", m^3/s)), title = "月度流量箱线图 - 观测值vs模拟值", fill = "数据类型" ) + scale_fill_manual(values = c("observed" = "#1f77b4", "simulated" = "#ff7f0e")) + # 自定义对比色 theme_minimal() # 展示图形 print(combined_boxplot)
方式2:用patchwork拼接独立子图到同一画布
如果希望保留两个独立箱线图的结构,仅将它们放在同一画布展示,使用patchwork包实现拼接:
# 安装并加载patchwork(首次使用需安装) # install.packages("patchwork") library(patchwork) # 保留原代码的两个独立箱线图 monthly_observed_boxplot <- ggplot(seasons, aes(x = Month)) + geom_boxplot(aes(y = observed, fill = Month), show.legend = F, alpha = 0.5) + labs( x = "月份", y = expression(paste("流量, ", m^3/s)), title = "月度箱线图 - 观测值" ) + theme_minimal() monthly_simulated_boxplot <- ggplot(seasons, aes(x = Month)) + geom_boxplot(aes(y = simulated, fill = Month), show.legend = F, alpha = 0.5) + labs( x = "月份", y = expression(paste("流量, ", m^3/s)), title = "月度箱线图 - 模拟值" ) + theme_minimal() # 拼接图形:+表示横向并排,/表示纵向上下排列 combined_plot <- monthly_observed_boxplot + monthly_simulated_boxplot + plot_annotation( title = "观测值与模拟值月度箱线图", theme = theme(plot.title = element_text(hjust = 0.5)) ) # 展示图形 print(combined_plot)
关键提示
- 原代码中
seasons的Month列需确保是两位字符格式(如"01"而非"1"),否则季节分类会出错,建议用format(time, "%m")生成。 - 方式1适合直接对比观测与模拟数据的分布差异;方式2适合保留两个图的独立性,便于分别查看细节。
内容的提问来源于stack exchange,提问作者Kamal Ziaul
相关产品推荐
相关产品推荐

