T–S diagram(温盐图解)是研究海洋水团、海水混合时的一种图解,物理海洋学上经常用到,以温度(T)为纵坐标,盐度(S)为横坐标。绘制T–S diagram常用ODV软件,然而ODV实在太......。下面提供R语言绘制法。
#先加载包 library(testthat); library(gsw); library(oce) library(ggplot2); library(stringr); library(dplyr); library(plyr) #选择GSW;Oceanographic Analysis with R: The oceanographic community has a choice of two sets of formulae for calculating seawater properties: the UNESCO formulation, popularized in the 1980s, and the Gibbs-SeaWater (GSW) formulation, proposed in 2010. options(oceEOS = 'gsw')
#读取CTD数据(cnv格式) setwd("D:/R/Data/Ocean/ctd") #该文件夹共4个文件,"S1.cnv" "S2.cnv" "S3.cnv" "S4.cnv" temp <- list.files( pattern = ".cnv")
下面提供两种绘制方法
方案一:oce包绘图
ctds<- vector("list", length(temp)) for (i in 1: length(temp)) { Cast <- read.oce ( temp[i] ) #str(Cast) #查看数据结构, cnv文件由metadata、data、processingLog三部分构成。 #读取文件名和经纬度信息;下面4行代码需根据cnv的不同格式作相应调整。 Filename <- str_replace(temp[i], '\\.cnv', '') #字符串替换 Geo <- unlist (str_split(Cast@metadata$header[20 : 21],pattern = ' ')) Lon <- as.numeric(Geo[3]) + as.numeric(Geo[4])/60 + as.numeric(Geo[5]) / 3600 Lat <- as.numeric(Geo[8]) + as.numeric(Geo[9])/60 + as.numeric(Geo[10]) / 3600 #读取数据 ctds[[i]] <- as.ctd( salinity = Cast@data$salinity, temperature = Cast@data$temperature, pressure = Cast@data$pressure, type = "SBE", station = Filename, longitude = Lon, latitude = Lat, deploymentType = "profile") rm( Filename, Geo, Lon, Lat) } #合并所有CTD数据 Data0 <- as.section(ctds) summary(Data0)
#绘图 plotTS(Data0, nlevels = 9, grid = FALSE, bg = "transparent", pch = 16, cex = 0.5, col.rho = "lightgray", cex.rho = 1, lty.rho = 1)
方案二:ggplot2包绘图
#建立空白数据框 Data1 <- data.frame(Station = character(0), Lon = numeric(0), Lat = numeric(0), Pressure = numeric(0), Temperature = numeric(0), Salinity = numeric(0), SA = numeric(0), CT = numeric(0)) for (i in 1: length(temp)) { Cast <- read.oce (temp[i]) #str(Cast) #查看数据结构, cnv文件由metadata、data、processingLog三部分构成。 #读取文件名和经纬度信息;下面4行代码需根据cnv的不同格式作相应调整。 Filename <- str_replace(temp[i], '\\.cnv', '') #字符串替换 Geo <- unlist (str_split(Cast@metadata$header[20 : 21],pattern = ' ')) Lon <- as.numeric(Geo[3]) + as.numeric(Geo[4])/60 + as.numeric(Geo[5]) / 3600 Lat <- as.numeric(Geo[8]) + as.numeric(Geo[9])/60 + as.numeric(Geo[10]) / 3600 #提取数据到data.frame data.tem <- data.frame(Station = Filename, Lon = Lon, Lat = Lat, Pressure = Cast@data$pressure, Temperature = Cast@data$temperature, Salinity = Cast@data$salinity) #计算Absolute Salinity和Conservative Temperature data.tem$SA <- gsw_SA_from_SP(data.tem$Salinity, data.tem$Pressure, longitude = Lon, latitude = Lat) data.tem$CT <- gsw_CT_from_t (SA = data.tem$SA, t = data.tem$Temperature, p = data.tem$Pressure) #合并数据 Data1 <- rbind.fill(Data1, data.tem) rm( Filename, Geo, Lon, Lat) }
#构建σ0等密度线数据 # make TS long table TS <- expand.grid( SA = seq( floor( min( Data1$SA )), ceiling( max( Data1$SA )), length.out = 100), CT = seq( floor( min( Data1$CT )) - 3, ceiling( max( Data1$CT )) + 3, length.out = 100) ) #为了显示最上和最下的等密度线,CT的范围选择+-3 TS$Density <- gsw_rho(TS$SA, TS$CT , 0) - 1000 #选择拟绘出的等密度线 isopycnals <- subset(TS, round(SA,1) == (ceiling(max(TS$SA))-0.8) & #等密度线加标注的位置的x轴坐标,数值0.8根据图片效果作相应调整 round(Density,1) %in% seq(min(round(TS$Density*2)/2), max(round(TS$Density*2)/2), by = 1)) #选择plot将绘出的等密度线上的数据 isopycnals$Density <- round(isopycnals$Density, 1) #保留一位小数 isopycnals <- aggregate(CT ~ Density, isopycnals, mean) #相同Density的CT值求均值
#绘图 p <- ggplot() + geom_contour(data =TS, aes(x = SA, y = CT, z = Density), col = "grey", linetype = "dashed", breaks = seq(min(round(TS$Density*2)/2), max(round(TS$Density*2)/2), by = 1)) + geom_text(data = isopycnals, aes(x = 35.2, y = CT, label = Density), hjust = "inward", vjust = 0, col = "grey60", angle = 15 ) + geom_point(data=Data1, aes(SA, CT, col = Station)) p;
#细节完善 p + scale_x_continuous(name = "Absolute Salinity [g/kg]", limits = c(33.4, 35.2)) + scale_y_continuous(name = "Conservative Temperature [°C]", limits = c(0, 32),breaks = seq(5, 30, 5)) + theme_bw() + annotate(geom = "text", x = 33.7, y = 32, label = "20", hjust = "inward", vjust = 0, col = "grey60", angle = 15) + annotate(geom = "text", x = 35.1, y = 32, label = "21", hjust = "inward", vjust = 0, col = "grey60", angle = 15) + theme(text = element_text(size = 14), axis.text = element_text(size = 12), panel.grid = element_blank())
两种方法比较,方案一简单,但用不同颜色标记不同站位比较困难;方案二颜色美观,但总体较繁琐(尤其是等密度线)。欢迎提出更好的解决办法。
作者:逍遥尐生
链接:https://www.jianshu.com/p/eb5ad2c3d0b4