【数据处理】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")
浙公网安备 33010602011771号