You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何提取GDAL_TEMPORAL_STOP为NetCDF创建时间变量并合并文件

解决无时间变量的NetCDF文件合并并添加时间维度的问题

我帮你整理了两种Python实现的方案,优先推荐用xarray(更简洁高效),也提供了netCDF4的底层实现方法,都能帮你把每个文件的GDAL_TEMPORAL_STOP全局属性转成时间变量,再合并所有文件。


方法一:使用xarray(推荐)

xarray对NetCDF的批量处理和维度管理非常友好,几步就能完成你的需求:

步骤1:导入依赖库

import xarray as xr
import pandas as pd
import glob

步骤2:定义读取单个文件的函数

这个函数会读取NetCDF文件,从全局属性中提取GDAL_TEMPORAL_STOP,将其转换为时间对象,然后给数据集添加时间维度:

def read_nc_with_time(file_path):
    # 读取NetCDF文件
    ds = xr.open_dataset(file_path)
    # 提取全局属性中的时间字符串
    time_str = ds.attrs['GDAL_TEMPORAL_STOP']
    # 转换为pandas datetime对象
    time = pd.to_datetime(time_str)
    # 给数据集添加时间维度(将原二维数据扩展为三维)
    ds = ds.expand_dims(time=[time])
    # 重命名Band1为更有意义的名字(可选,比如VCI)
    ds = ds.rename({'Band1': 'VCI'})
    return ds

步骤3:批量读取并合并所有文件

# 获取所有NetCDF文件的路径(替换成你的文件路径通配符)
nc_files = glob.glob('path/to/your/netcdf/files/*.nc')

# 批量读取所有文件
datasets = [read_nc_with_time(file) for file in nc_files]

# 按时间维度拼接所有数据集
combined_ds = xr.concat(datasets, dim='time')

# (可选)如果文件顺序混乱,按时间排序
combined_ds = combined_ds.sortby('time')

# 保存合并后的文件
combined_ds.to_netcdf('combined_vci_data.nc')

关键细节解释

  • expand_dims:将原有的(lat, lon)二维数据扩展为(time, lat, lon)三维,这样所有文件的数据就能按时间维度无缝拼接。
  • pd.to_datetime:自动识别YYYY-MM-DD格式的时间字符串,转换成xarray能识别的标准时间类型。
  • 合并后可以用ncdump -h combined_vci_data.nc查看,会看到新增的time变量和维度,每个时间值对应原文件的GDAL_TEMPORAL_STOP

方法二:使用netCDF4(底层实现)

如果你需要更精细的控制(比如自定义变量属性、调整存储格式),可以用netCDF4库手动创建时间变量和合并数据:

步骤1:导入依赖库

import netCDF4 as nc
import numpy as np
import pandas as pd
import glob

步骤2:预读取所有文件的时间和数据信息

nc_files = glob.glob('path/to/your/netcdf/files/*.nc')

# 存储所有时间和数据
times = []
vci_data = []
lat = None
lon = None
crs_attrs = None

for file in nc_files:
    with nc.Dataset(file, 'r') as src:
        # 只读取一次经纬度和CRS属性(所有文件维度一致)
        if lat is None:
            lat = src.variables['lat'][:]
            lon = src.variables['lon'][:]
            crs_attrs = src.variables['crs'].__dict__.copy()
        # 提取时间属性并转换
        time_str = src.GDAL_TEMPORAL_STOP
        times.append(pd.to_datetime(time_str))
        # 读取Band1数据
        vci_data.append(src.variables['Band1'][:])

# 将时间转换为NetCDF标准的数值格式(秒为单位的时间戳)
time_units = 'seconds since 1970-01-01 00:00:00'
time_vals = nc.date2num(times, units=time_units)

步骤3:创建合并后的NetCDF文件

# 创建新的NetCDF文件
with nc.Dataset('combined_vci_data.nc', 'w', format='NETCDF4') as dst:
    # 创建维度
    dst.createDimension('time', len(times))
    dst.createDimension('lat', len(lat))
    dst.createDimension('lon', len(lon))

    # 创建时间变量
    time_var = dst.createVariable('time', 'f8', ('time',))
    time_var.setncatts({
        'standard_name': 'time',
        'long_name': 'time',
        'units': time_units,
        'calendar': 'gregorian'
    })
    time_var[:] = time_vals

    # 创建纬度变量
    lat_var = dst.createVariable('lat', 'f8', ('lat',))
    lat_var.setncatts({
        'standard_name': 'latitude',
        'long_name': 'latitude',
        'units': 'degrees_north'
    })
    lat_var[:] = lat

    # 创建经度变量
    lon_var = dst.createVariable('lon', 'f8', ('lon',))
    lon_var.setncatts({
        'standard_name': 'longitude',
        'long_name': 'longitude',
        'units': 'degrees_east'
    })
    lon_var[:] = lon

    # 创建CRS变量
    crs_var = dst.createVariable('crs', 'c', ())
    crs_var.setncatts(crs_attrs)

    # 创建VCI变量(原Band1)
    vci_var = dst.createVariable('VCI', 'b', ('time', 'lat', 'lon',))
    vci_var.setncatts({
        'long_name': 'Vegetation Condition Index',
        '_Unsigned': 'true',
        'valid_range': np.array([0, 255], dtype=np.int16),
        '_FillValue': np.byte(0),
        'VCI_CLASS': 'DATA',
        'VCI_MISSING_VALUE': 251,
        'VCI_NB_BYTES': 'Uint8',
        'VCI_OFFSET': -5,
        'VCI_ORDER_BYTES': 1,
        'VCI_PRODUCT': 'VCI',
        'VCI_SCALING_FACTOR': 0.5,
        'grid_mapping': 'crs'
    })
    vci_var[:] = np.array(vci_data)

    # (可选)复制原文件的全局属性
    with nc.Dataset(nc_files[0], 'r') as src:
        for attr_name in src.ncattrs():
            dst.setncattr(attr_name, src.getncattr(attr_name))

合并完成后,你可以用ncdump -h combined_vci_data.nc验证结果,新增的time变量会正确对应每个原文件的GDAL_TEMPORAL_STOP属性值,不会再出现时间戳为0的问题。

内容的提问来源于stack exchange,提问作者Dimitris Kasabalis

火山引擎 最新活动