R语言学习笔记--利用R绘制T–S diagram

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())       
两种方法比较,方案一简单,但用不同颜色标记不同站位比较困难;方案二颜色美观,但总体较繁琐(尤其是等密度线)。欢迎提出更好的解决办法。
主要参考资料:ggTSKelley D E, 2018. Oceanographic Analysis with R
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,284评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,115评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,614评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,671评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,699评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,562评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,309评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,223评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,668评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,859评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,981评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,705评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,310评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,904评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,023评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,146评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,933评论 2 355

推荐阅读更多精彩内容