R新手求助:如何处理同列多变量并绘制带设备区分的水质时序图
解决思路:数据整理 + 时间序列绘图
第一步:数据清洗与整理
你的数据第一行是单位说明,需要先移除;然后把日期转为R能识别的格式,把数值列转为数值型(处理像<0.009这类特殊值),最后把两台设备的指标合并到同一结构里,方便后续绘图。
1.1 加载必要包
library(tidyverse) # 包含数据处理工具dplyr和绘图工具ggplot2 library(lubridate) # 简化日期格式转换
1.2 导入并清洗数据
先把你提供的数据集赋值给变量,再执行清洗步骤:
# 赋值你提供的数据集 df <- structure(list(Sample.Id = c(NA, "2", "2", "2", "2", "2", "2", "2", "2", "2", "2", "3", "3", "3", "3", "3", "3", "3", "3", "3"), Sampling..Date = c(NA, "08-Sep-14", "14-Oct-14", "02-Nov-14", "21-Nov-14", "03-Dec-14", "15-Dec-14", "11-Jan-15", "08-Feb-15", "01-Mar-15", "06-Apr-15", "03-Sep-14", "08-Sep-14", "14-Oct-14", "02-Nov-14", "21-Nov-14", "03-Dec-14", "15-Dec-14", "11-Jan-15", "26-Jan-15"), Tot.P = c("µg/ml", "0.002", "0.017", "0.035", "0.04", "0.059", "0.155", "0.021", "0.022", "0.025", "<0.009", "0.021", "0.003", "0.036", "0.141", "0.041", "0.044", "0.01", "0.023", "0.016"), DOC = c("µg/ml", NA, "12.3", "13.4", "12.5", "9.9", "14.7", "8.8", "8.3", "0.026", "7.5", "13.4", NA, "14.6", "16.6", "14.7", "12.6", "12.6", "10.6", "11.4"), Tot.N = c("µg/ml", NA, "3.63", "4.12", "3.98", "4.08", "3.38", "3.63", "4.88", "8.3", "2.74", "2.48", NA, "3.07", "3.38", "3.3", "3.43", "2.19", "2.77", "4.25"), DOC.1 = c("µg/ml", "13.6", NA, NA, NA, NA, NA, NA, NA, NA, NA, "14.44", "16.85", NA, NA, NA, NA, NA, NA, NA), Tot.P.1 = c("µg/ml", "0.053", NA, NA, NA, NA, NA, NA, NA, NA, NA, "0.08", "0.071", NA, NA, NA, NA, NA, NA, NA), Total.N = c("µg/ml", "3.363", NA, NA, NA, NA, NA, NA, NA, NA, NA, "2.645", "2.637", NA, NA, NA, NA, NA, NA, NA)), row.names = c(NA, 20L), class = "data.frame") # 1. 移除第一行(单位说明行) df_clean <- df[-1, ] # 2. 转换日期格式:将字符型日期转为R可识别的Date类型 df_clean$Sampling..Date <- dmy(df_clean$Sampling..Date) # 3. 处理特殊数值:去除"<"符号后转为数值型 convert_to_numeric <- function(x) { x <- gsub("<", "", x) as.numeric(x) } # 对所有指标列应用转换函数 df_clean <- df_clean %>% mutate( # 设备1的指标 Tot.P = convert_to_numeric(Tot.P), DOC = convert_to_numeric(DOC), Tot.N = convert_to_numeric(Tot.N), # 设备2的指标(统一列名,方便后续合并) Tot.P.1 = convert_to_numeric(Tot.P.1), DOC.1 = convert_to_numeric(DOC.1), Total.N = convert_to_numeric(Total.N), # 站点ID转为因子,方便分组 Sample.Id = as.factor(Sample.Id) )
1.3 重塑数据(宽转长)
把当前的宽格式数据转为长格式,让ggplot2能按指标、设备分组绘图:
# 整理设备1的数据 device1_data <- df_clean %>% select(Sample.Id, Sampling..Date, Tot.P, DOC, Tot.N) %>% pivot_longer(cols = c(Tot.P, DOC, Tot.N), names_to = "Indicator", values_to = "Value") %>% mutate(Device = "设备1") %>% drop_na(Value) # 移除缺失值 # 整理设备2的数据(重命名列名和设备1统一) device2_data <- df_clean %>% select(Sample.Id, Sampling..Date, Tot.P.1, DOC.1, Total.N) %>% rename(Tot.P = Tot.P.1, DOC = DOC.1, Tot.N = Total.N) %>% pivot_longer(cols = c(Tot.P, DOC, Tot.N), names_to = "Indicator", values_to = "Value") %>% mutate(Device = "设备2") %>% drop_na(Value) # 合并两台设备的数据 final_data <- bind_rows(device1_data, device2_data)
第二步:提取设备时段(用于绘制阴影)
从整理好的数据中提取每个站点、设备的时间范围,用来绘制区分时段的阴影:
time_ranges <- final_data %>% group_by(Sample.Id, Device) %>% summarise( start_date = min(Sampling..Date), end_date = max(Sampling..Date) ) %>% ungroup()
第三步:绘制时间序列图(带设备时段阴影)
用ggplot2绘制分站点、分指标的时间序列图,同时用阴影区分不同设备的监测时段:
ggplot(final_data, aes(x = Sampling..Date, y = Value, color = Device)) + # 绘制设备时段阴影(透明度0.2避免遮挡数据) geom_rect(data = time_ranges, aes(xmin = start_date, xmax = end_date, ymin = -Inf, ymax = Inf, fill = Device), alpha = 0.2, inherit.aes = FALSE) + # 绘制数据点和折线 geom_point(size = 2) + geom_line(alpha = 0.7) + # 按指标和站点分面展示,y轴自适应数据范围 facet_grid(Indicator ~ Sample.Id, scales = "free_y") + # 设置图表标签 labs(x = "采样日期", y = "浓度 (µg/ml)", color = "设备", fill = "设备") + # 优化样式:旋转x轴日期避免重叠 theme_minimal() + theme(axis.text.x = element_text(angle = 45, hjust = 1))
代码说明
geom_rect用来绘制阴影时段,inherit.aes = FALSE避免继承主图层的颜色映射;facet_grid将不同指标(总磷/总氮/DOC)和站点分开显示,scales="free_y"让每个子图的y轴适配自身数据;- 旋转x轴日期是为了避免日期标签重叠,提升可读性。
额外提示
如果你的完整数据(2014-2022)包含更多站点和时段,只需替换初始的df数据集即可复用代码,程序会自动识别每个设备的时间范围并绘制对应阴影。
内容的提问来源于stack exchange,提问作者Forsaken_PhD
相关产品推荐
相关产品推荐

