【数据处理】NetCDF 文件:从入门到精通

写本文的目的就是想了解一下nc文件,其内部构造到底是什么样子的?
简单总结就是最主要的就是Variables,比如海温(temperature),然后这个变量可能包含多个维度Dimensions,
比如time,lat,lon,level等等。然后每一个变量都有与之对应的数据,这样子的话其实也就是四组数据,
他们之间并没有直接的联系,此次就有一个很重要的Coordinates,坐标就可以把这些维度变量与海温变量之间联系起来,这样就很方便后面的操作,实现自描述!

 源出处:https://blog.csdn.net/Small___ming/article/details/147896808

一、什么是 NetCDF?

(一)定义

NetCDF(Network Common Data Form)是一种自描述、平台无关、二进制格式的数据文件,广泛应用于气象、海洋、地球科学等领域。它能够存储多维科学数据(如时间、纬度、经度、高度等),并且自带元数据信息,便于数据交换和共享。

(二)特点
自描述性(Self-describing):包含变量名、维度、单位、注释等元数据。
支持多维数组(Multidimensional arrays):适合表示时空数据。
跨平台兼容性强:支持多种操作系统和编程语言。
高效读写:适用于大规模科学数据处理。

 

二、NetCDF 文件的结构

NetCDF 文件的核心结构由以下四个部分组成,每部分的功能和区别如下:

 

组成部分作用特点示例
1. 维度(Dimensions) 定义数据的维度(如时间、纬度、经度等),是变量的"骨架"。 - 可以是固定长度或无限长度(UNLIMITED)。
- 每个变量必须绑定到维度。
time = 12, lat = 73, lon = 144
2. 变量(Variables) 存储实际的多维数据(如温度、风速等),是数据的主体。 - 每个变量关联到一个或多个维度。
- 数据类型支持 int, float, double, char 等。
temperature(time, lat, lon)
3. 属性(Attributes) 描述变量或文件的元数据(如单位、长名称、来源等)。 - 分为全局属性(描述整个文件)和局部属性(描述变量)。
- 用于增强数据的可读性和互操作性。
units = "K", long_name = "Surface Temperature"
4. 数据(Data) 实际存储在变量中的数值,按维度排列。 - 数据块按需读取,支持高效访问子集。 temperature[0, 0, 0] = 285.3

 

示例:一个 NetCDF 文件可能包含如下结构:

 

dimensions:
    time = 12 ;
    lat = 73 ;
    lon = 144 ;

variables:
    float temperature(time, lat, lon) ;
        temperature:units = "K" ;
        temperature:long_name = "Surface Air Temperature" ;
    double time(time) ;
        time:units = "months since 2000-01-01" ;
    float lat(lat) ;
        lat:units = "degrees_north" ;
    float lon(lon) ;
        lon:units = "degrees_east" ;

 区别总结

维度变量属性数据
定义数据的轴(如时间、空间) 存储具体科学数据 描述数据的元信息 实际的数值内容
是变量的"结构基础" 依赖维度定义 附加在变量或文件上 由变量存储
例如:time = 12 例如:temperature(time, lat, lon) 例如:units = "K" 例如:285.3

 

 

如何实现自描述的?-----Coordinates
在 NetCDF 文件中,坐标(Coordinates) 是用于描述数据空间、时间或其他维度位置的关键元数据。它们通过 坐标变量(Coordinate Variables) 和 维度(Dimensions) 的组合,帮助定义数据的物理位置(如经纬度、时间、高度等),从而实现数据的多维定位和可视化。以下是其作用和细节的详细说明:

1. 坐标的作用
(1) 定义数据的空间/时间位置
坐标变量通常与维度一一对应,用于描述数据在物理空间或时间上的分布。例如:

空间坐标:经度(lon)、纬度(lat)、高度(height)。
时间坐标:时间(time),如 2025-05-12。
其他维度:深度(depth)、压力(pressure)等。
支持数据的多维索引
通过坐标变量,可以快速定位数据在某个位置(如某经纬度、某时间点)的值。例如:

data.sel(lat=30, lon=120, time='2025-05-12')  # 使用 xarray 选取特定位置的数据

(2) 辅助 GIS 和科学工具的可视化
GIS 软件(如 ArcGIS、QGIS)和科学工具(如 Python 的 matplotlib、cartopy)依赖坐标变量来:

正确解析数据的 空间参考系统(地理坐标系或投影坐标系)。
自动匹配地图投影,避免数据错位(如经纬度与投影坐标不一致导致的偏移)。
(3) 遵循 CF 约定(Climate and Forecast Metadata Conventions)
NetCDF 社区广泛采用 CF 元数据约定,要求通过坐标变量的属性(如 units、standard_name)明确描述数据的物理意义。例如:

lat = rootgrp.createVariable("lat", "f4", ("lat",))
lat.units = "degrees_north"  # 表示纬度单位
lat.standard_name = "latitude"  # 标准名称
2. 坐标变量的定义方式

(1) 坐标变量(Coordinate Variables)

  • 定义:与维度同名的一维变量,用于描述该维度的物理坐标。
  • 示例:
  • # 定义维度
    lat_dim = rootgrp.createDimension("lat", 73)
    # 创建坐标变量
    lat = rootgrp.createVariable("lat", "f4", ("lat",))
    lat[:] = np.arange(-90, 90, 2.5)  # 纬度值

    (2) 辅助坐标变量(Auxiliary Coordinate Variables)

    • 定义:非维度同名的变量,用于描述复杂坐标(如三维经纬度、球面坐标)。
    • 示例:
      # 定义三维数据的经纬度(如球面坐标)
      lons = rootgrp.createVariable("longitude", "f4", ("time", "lat", "lon"))
      lats = rootgrp.createVariable("latitude", "f4", ("time", "lat", "lon"))

       

(2) 辅助坐标变量(Auxiliary Coordinate Variables)

  • 定义:非维度同名的变量,用于描述复杂坐标(如三维经纬度、球面坐标)。
  • 示例:
  • # 定义三维数据的经纬度(如球面坐标)
    lons = rootgrp.createVariable("longitude", "f4", ("time", "lat", "lon"))
    lats = rootgrp.createVariable("latitude", "f4", ("time", "lat", "lon"))

     

3. 坐标变量的关键属性 为确保数据的可读性和兼容性,坐标变量需要设置以下属性:

 

属性作用示例
units 描述坐标单位 "degrees_east"、"m"、"hours since 2000-01-01"
standard_name 标准名称(CF 约定) "latitude"、"time"
long_name 详细描述 "Surface Air Temperature"
grid_mapping 定义投影参数(用于投影坐标系) "projection" 变量的名称
bounds 定义坐标的范围(如经纬度网格的边界) "lat_bnds"、"lon_bnds"

 

 

4. 坐标与空间参考系统(CRS)的关系

(1) 地理坐标系(GCS)

  • 如果坐标变量的单位是 degrees_east(经度)和 degrees_north(纬度),则默认使用 WGS 1984 地理坐标系。
  • 示例:
    lon.units = "degrees_east"
    lat.units = "degrees_north"

     

(2) 投影坐标系(PCS)

  • 如果坐标变量的 standard_name 是 projection_x_coordinate 和 projection_y_coordinate,并配合 grid_mapping 属性,则表示投影坐标系。
  • 示例:
    x = rootgrp.createVariable("x", "f4", ("x",))
    x.standard_name = "projection_x_coordinate"
    y = rootgrp.createVariable("y", "f4", ("y",))
    y.standard_name = "projection_y_coordinate"
    grid_mapping = rootgrp.createVariable("projection", "i4")
    grid_mapping.grid_mapping_name = "lambert_conformal_conic"

     

1

5. 实际应用中的注意事项
(1) 遵循 CF 约定

为坐标变量设置 standard_name 和 units,确保与其他工具兼容。
对于时间变量,使用标准时间格式(如 days since 2000-01-01)。
(2) 避免坐标错位

确保经纬度的范围和分辨率与数据匹配(如全球数据需覆盖 0°-360° 或 -180°-180°)。
使用 bounds 属性定义网格边界,避免插值错误。
(3) GIS 软件的兼容性

在 ArcGIS 中,若坐标变量未正确设置 units 或 grid_mapping,可能导致数据无法正确显示。
使用 Make NetCDF Table View 工具提取坐标信息,并通过插值算法(如 IDW)校正位置。
6. 代码示例:定义坐标变量
以下代码展示如何使用 netCDF4 库定义一个包含经纬度和时间坐标的 NetCDF 文件:

from netCDF4 import Dataset
import numpy as np

# 创建文件
rootgrp = Dataset("example.nc", "w", format="NETCDF4")

# 定义维度
time_dim = rootgrp.createDimension("time", None)
lat_dim = rootgrp.createDimension("lat", 73)
lon_dim = rootgrp.createDimension("lon", 144)

# 定义坐标变量
time = rootgrp.createVariable("time", "i4", ("time",))
lat = rootgrp.createVariable("lat", "f4", ("lat",))
lon = rootgrp.createVariable("lon", "f4", ("lon",))

# 写入数据
time.units = "days since 2000-01-01"
time[0] = 0
lat.units = "degrees_north"
lat[:] = np.arange(-90, 90, 2.5)
lon.units = "degrees_east"
lon[:] = np.arange(0, 360, 2.5)

# 关闭文件
rootgrp.close()
7. 总结

 

作用关键点
定义数据位置 通过坐标变量(如经纬度、时间)描述数据的空间/时间分布
多维索引 支持按坐标选取数据子集(如 data.sel(lat=30, lon=120))
空间参考 配合 units 和 grid_mapping 属性定义地理或投影坐标系
兼容性 遵循 CF 约定,确保不同工具(如 GIS、Python 库)正确解析数据

 

 

通过合理设置坐标变量,NetCDF 文件能够高效存储和共享科学数据,并确保其在分析和可视化中的准确性。

三、NetCDF 常用工具介绍

(一) 命令行工具(CLI)

1. ncdump

查看 nc 文件内容的最常用命令。

ncdump -h filename.nc       # 查看头信息(metadata)
ncdump -v varname filename.nc  # 查看某个变量的内容
2. ncks (来自 NCO)

提取子集、合并文件、修改变量。

ncks -d lat,30,50 -d lon,-120,-80 input.nc output.nc   # 提取区域子集
3. cdo (Climate Data Operators)

气候数据处理工具,可进行插值、统计、合并等操作。

cdo timmean input.nc output.nc     # 计算时间平均
cdo seltimestep,1/12 input.nc output.nc  # 提取前12个时间步

(二) 图形化工具
1. Panoply(NASA)
免费、跨平台、可视化 nc 文件数据。

2. QGIS + GDAL
可用于加载并显示 nc 格式的地理空间数据。

四、使用 Python 操作 NetCDF 文件
Python 是处理 NetCDF 的首选语言之一,主要依赖库包括:

netCDF4: Python 接口,功能强大
xarray: 封装了 netCDF4,更易用
numpy: 支持数组运算
matplotlib/cartopy: 可视化
(一) 安装依赖

pip install netCDF4 xarray matplotlib cartopy

五、实战教程:读取、分析、绘制 NetCDF 数据
我们以一个全球气温数据 .nc 文件为例,完成以下任务:

读取 nc 文件
查看变量与维度
提取某个月份的气温数据
绘制全球气温分布图
(一) 步骤 1:准备数据
你可以使用 NOAA 或 CMIP6 提供的公开数据,比如 air.2m.mon.mean.nc。

(二)步骤 2:读取 nc 文件(使用 xarray)

import xarray as xr

# 加载 nc 文件
ds = xr.open_dataset('air.2m.mon.mean.nc')

# 显示基本信息
print(ds)

输出类似:

<xarray.Dataset>
Dimensions:  (lat: 73, lon: 144, time: 852)
Coordinates:
  * lat      (lat) float32 -90.0 -87.5 -85.0 ... 85.0 87.5 90.0
  * lon      (lon) float32 0.0 2.5 5.0 ... 355.0 357.5
  * time     (time) datetime64[ns] 1979-01-01 ... 2020-12-01
Data variables:
    air      (time, lat, lon) float32 ...

(三) 步骤 3:提取某月份的数据(如 2000 年 1 月)

# 选择 2000年1月
data = ds['air'].sel(time='2000-01-01', method='nearest')

# 查看数据形状
print(data.shape)  # 输出:(73, 144)

# 转换为 numpy 数组
temp_data = data.values  # shape: (73, 144)

(四) 步骤 4:绘制全球气温分布图

import matplotlib.pyplot as plt
import cartopy.crs as ccrs

# 设置绘图投影
fig = plt.figure(figsize=(12, 6))
ax = fig.add_subplot(111, projection='platecarree')

# 绘制等值线图
cs = ax.contourf(data.lon, data.lat, temp_data, cmap='coolwarm', transform=ccrs.PlateCarree())

# 添加海岸线
ax.coastlines()

# 添加颜色条
plt.colorbar(cs, orientation='horizontal', label='Temperature (K)')
plt.title('Global Surface Air Temperature - January 2000')
plt.show()

六、进阶技巧:创建和写入 NetCDF 文件

(一) 示例:创建一个新的 nc 文件并写入数据

from netCDF4 import Dataset
import numpy as np

# 创建新文件
rootgrp = Dataset("example_output.nc", "w", format="NETCDF4")

# 定义维度
lat_dim = rootgrp.createDimension("lat", 73)
lon_dim = rootgrp.createDimension("lon", 144)
time_dim = rootgrp.createDimension("time", None)  # 无限长维度

# 定义变量
latitudes = rootgrp.createVariable("lat", "f4", ("lat",))
longitudes = rootgrp.createVariable("lon", "f4", ("lon",))
times = rootgrp.createVariable("time", "i4", ("time",))
temps = rootgrp.createVariable("temperature", "f4", ("time", "lat", "lon"))

# 写入变量数据
lats = np.arange(-90, 91, 2.5)
lons = np.arange(0, 360, 2.5)
latitudes[:] = lats
longitudes[:] = lons
times[0] = 0

# 构造一个简单的二维温度场
temps[0, :, :] = np.random.rand(73, 144) * 30 + 273  # 单位 K

# 添加属性
temps.units = "Kelvin"
temps.long_name = "Surface Air Temperature"

# 关闭文件
rootgrp.close()

(二) 使用 xarray 简化操作

import xarray as xr

# 创建 Dataset
ds = xr.Dataset(
    {
        "temperature": (["time", "lat", "lon"], [temp_data]),
    },
    coords={
        "time": [0],
        "lat": lats,
        "lon": lons,
    },
    attrs={"description": "Example using xarray"},
)

# 保存为 .nc 文件
ds.to_netcdf("example_output_xarray.nc")

 

posted @ 2025-06-17 16:57  嚼_嚼_籽  阅读(523)  评论(0)    收藏  举报