如何使用 R 中的 terra::extract() 从多个 netcdf 文件中提取多年特定日期的海面温度点数据

问题描述 投票:0回答:1

我已从 NASA 海洋颜色项目下载了多个 Lm3 4 km netcdf 文件 (n = 4640),用于了解海面温度。

class       : SpatRaster 
dimensions  : 766, 709, 1  (nrow, ncol, nlyr)
resolution  : 0.04165021, 0.04165796  (x, y)
extent      : 24.61, 54.14, 5.8, 37.71  (xmin, xmax, ymin, ymax)
coord. ref. : lon/lat WGS 84 
source      : AQUA_MODIS.20120101.L3m.DAY.SST.x_sst.nc:sst 
varname     : sst (Sea Surface Temperature) 
name        :      sst 
unit        : degree_C 

我的数据涵盖 2012 年至 2024 年红海 82 公里区域,我想提取特定日期的海面温度点数据。

我已使用下面的代码成功从 netcdf 文件中提取了海面温度值,但我不确定是否只是从第一个 netcdf 层提取值而不是循环遍历所有文件(1:4640),我不确定如何将时间元素(“日期”列)与多年来特定日期的点数据合并。

由于所有权问题,我无法共享数据。

library(terra)
library(lubricate)

#Download Sea Surface Temperature 
folder_SST<-"~/Documents/GIS_Data/SST/requested_files"
files_SST <-list.files(folder_SST, pattern='*.nc', full.names ="TRUE")

#Loop through all the file paths and the AQUA MODIS netcdf4 files to gain access to them:
for (file in files_SST) {
  nc_SST=open.nc(files_SST)
  print.nc(nc_SST)
}

#Select the sea surface temperature values from AQUA MODIS files 
SSTs <- terra::rast(files_SST[1], "sst")

#Make the dataframe a spatial object of class = "sf" with a CRS of 4326
Ds_Points <- st_as_sf(x=MyDf, 
                      coords = c("Longitude_E_DD", "Latitude_N_DD"), 
                      crs = 4326)

#Format the dates in the dataframe 
#Get dates
MyDf <- MyDf %>% mutate(Dates = as.Date(as.character(MyDf$Date), format = "%d/%m/%Y"))

#Extract the SST values from the AQUA MODIS files 
SSTs_Data <- terra::extract(SSTs, Ds_Points)

所需输出:

   Survey_Number       Dates Longitude_E_DD Latitude_N_DD    SST
              1   2012-08-01       33.89083      27.26778 23.635
              2   2012-06-02       33.86782      27.40854 23.640
              3   2012-02-07       33.86230      27.44623 23.690
              4   2012-02-12       33.88653      27.26957 23.635
              5   2012-02-13       33.88766      27.26848 23.635
              6   2012-02-14       33.85000      27.36111 23.780
              7   2012-02-15       33.86177      27.41302 23.640
r gis raster netcdf
1个回答
0
投票

在您的代码中,您确实只从第一个 netcdf 文件中提取值。脚本中的这一行:

SSTs <- terra::rast(files_SST[1], "sst")

意味着您正在加载 files_SST 列表中的第一个文件,并且仅在脚本的其余部分中使用该文件。您将需要使用“for 循环”来迭代每个文件。我在您的 Ds_Points 定义上方没有看到对 MyDf 的引用,因此我使用您所需结果中显示的前 4 个点的纬度/经度值手动创建了 MyDf。我还从给定来源下载了 3 个最新的 SST 文件以用于此目的。

这是我的解决方案:

library(tidyverse)
library(terra)
library(tidyterra)
library(sf)
library(ncdf4)
library(lubridate)
library(stringr)

# create vectors of longs and lats for sample points
# add these to MyDf, then convert MyDf to sf and save sf to Ds_Points
longs <- c(33.89083, 33.86782, 33.86230, 33.88653)
lats <- c(27.26778, 27.40854, 27.44623, 27.26957)

MyDf <- data.frame(longs, lats) %>%
  rename(
    Longitude_E_DD = longs,
    Latitude_N_DD = lats
  )

Ds_Points <- st_as_sf(x = MyDf, 
                      coords = c("Longitude_E_DD", "Latitude_N_DD"), 
                      crs = 4326)

######################################################################

# set path to data folder
# get sea surface temperature data files
folder_SST <- paste(here::here(), '/data', sep = '')
files_SST <- list.files(folder_SST, full.names ="TRUE")

# set column names in expected output df,
# then add them to new sst_df
cols <- c('Survey Number', 'Date', 'Longitude_E_DD', 'Latitude_N_DD', 'SST')

sst_df <- data.frame()

for (col in cols) {
  sst_df[1, col] <- NA 
}

######################################################################

# initialize index and survey_num
index <- 1
survey_num <- 1

# loop through all the AQUA MODIS netcdf4 files
for (file in files_SST) {
  # open file as raster and get sst layer
  nc_SST = rast(file, "sst")
  
  # get formatted date from file name
  date <- as.Date(as.character(str_split(tail(str_split(file, '/')[[1]], 1), '\\.')[[1]][2]), format = "%Y%m%d")
  
  # iterate over each point
  for (i in 1:nrow(Ds_Points)) {
    # get point
    d_point <- Ds_Points[i,]
    
    # get point's lat and long
    lon <- st_coordinates(d_point)[,'X']
    lat <- st_coordinates(d_point)[,'Y']
    
    # get SST at that point from SST file
    # must convert point geometry to spatvector to use in terra::extract function
    SST_data <- terra::extract(nc_SST, as_spatvector(d_point, geom = 'geometry', crs = st_crs(Ds_Points)))
    
    # insert data into sst_df at row index
    sst_df[index, 'Survey Number'] <- survey_num
    sst_df[index, 'Date'] <- as.character(date)
    sst_df[index, 'Longitude_E_DD'] <- lon
    sst_df[index, 'Latitude_N_DD'] <- lat
    sst_df[index, 'SST'] <- SST_data$sst
    
    # next row index
    index <- index + 1
  }

  # next survey number/file
  survey_num <- survey_num + 1
}

# show completed sst_df
sst_df

这是输出:

   Survey Number       Date Longitude_E_DD Latitude_N_DD    SST
               1 2024-10-28       33.89083      27.26778 26.980
               1 2024-10-28       33.86782      27.40854 27.000
               1 2024-10-28       33.86230      27.44623 27.075
               1 2024-10-28       33.88653      27.26957 26.980
               2 2024-10-30       33.89083      27.26778 27.055
               2 2024-10-30       33.86782      27.40854 27.005
               2 2024-10-30       33.86230      27.44623 27.060
               2 2024-10-30       33.88653      27.26957 27.055
               3 2024-11-01       33.89083      27.26778 27.265
               3 2024-11-01       33.86782      27.40854 27.220
               3 2024-11-01       33.86230      27.44623 27.165
               3 2024-11-01       33.88653      27.26957 27.265

此脚本查找每个 netcdf 文件的 Ds_Points 中每个点的 SST 值,然后将数据添加到 sst_df。有 4 个点,因此 3 个日期/SST 文件中的每一个都有 4 个 SST 值。该日期是从 netcdf 文件的文件名中提取的。我认为每个日期的调查编号都是唯一的。

请记住,考虑到您有多少个文件,这个特定的解决方案会有点慢,甚至更慢,具体取决于您有多少个点(因为它将迭代每个文件的每个点)。

© www.soinside.com 2019 - 2024. All rights reserved.