导入 NetCDF 文件和 OPeNDAP 数据
您可以使用多种方法从 netCDF 文件中读取数据。您可以通过编程方式使用 MATLAB® 高级 netCDF 函数或低级函数的 netCDF 库命名空间。您可以通过交互方式使用导入数据实时编辑器任务或(在 MATLAB Online™ 中)导入工具。
MATLAB NetCDF 功能
网络通用数据表 (NetCDF) 是一组软件库及与机器无关的数据格式,支持创建、访问和共享面向数组的科学数据。NetCDF 广泛用于工程和科学领域,这些领域需要一种标准的数据存储方式,以便共享数据。
MATLAB 高级函数简化了从 NetCDF 文件或 OPeNDAP NetCDF 数据源导入数据的过程。MATLAB 低级函数通过提供对 NetCDF C 库中例程的访问权限来实现对导入过程的更多控制。要有效地使用低级函数,您应该熟悉 NetCDF C 接口。NetCDF 文档可在 Unidata 网站上获取。
注意
有关导入具有单独的、不兼容格式的通用数据格式 (CDF) 文件的信息,请参阅Import CDF Files Using Low-Level Functions。
连接到 OPeNDAP 服务器时的安全注意事项
强烈建议您只连接到受信任的 OPeNDAP 服务器。自 R2020b 开始,默认情况下,MATLAB NetCDF 接口仅通过执行服务器证书和主机名验证连接到受信任的数据访问协议 (DAP) 端点。以前,当您访问 OPeNDAP 服务器时,默认情况下服务器证书和主机名验证都处于禁用状态。
如果要禁用服务器证书和主机名验证,请在当前目录的 .dodsrc
文件中添加以下行:
[mylocaltestserver.lab] HTTP.SSL.VALIDATE=0
这样,MATLAB NetCDF 接口会连接到在 URI mylocaltestserver.lab
中指定名称的 OPeNDAP 服务器,而无需对服务器证书或主机名执行任何验证。此更改将在以后的 MATLAB 会话中持续存在。
使用高级函数读取 NetCDF 文件
此示例说明如何使用高级函数显示和读取 NetCDF 文件的内容。
显示示例 NetCDF 文件 example.nc
的内容。
ncdisp('example.nc')
Source: \\matlabroot\toolbox\matlab\demos\example.nc Format: netcdf4 Global Attributes: creation_date = '29-Mar-2010' Dimensions: x = 50 y = 50 z = 5 Variables: avagadros_number Size: 1x1 Dimensions: Datatype: double Attributes: description = 'this variable has no dimensions' temperature Size: 50x1 Dimensions: x Datatype: int16 Attributes: scale_factor = 1.8 add_offset = 32 units = 'degrees_fahrenheit' peaks Size: 50x50 Dimensions: x,y Datatype: int16 Attributes: description = 'z = peaks(50);' Groups: /grid1/ Attributes: description = 'This is a group attribute.' Dimensions: x = 360 y = 180 time = 0 (UNLIMITED) Variables: temp Size: [] Dimensions: x,y,time Datatype: int16 /grid2/ Attributes: description = 'This is another group attribute.' Dimensions: x = 360 y = 180 time = 0 (UNLIMITED) Variables: temp Size: [] Dimensions: x,y,time Datatype: int16
ncdisp
显示文件中的所有组、维度和变量定义。无限维度用标签 UNLIMITED
标识。
从 peaks
变量中读取数据。
peaksData = ncread('example.nc','peaks');
显示有关 peaksData
输出的信息。
whos peaksData
Name Size Bytes Class Attributes peaksData 50x50 5000 int16
读取与变量相关联的 description
属性。
peaksDesc = ncreadatt('example.nc','peaks','description')
peaksDesc = z = peaks(50);
创建变量数据的三维曲面图。用 description
属性的值作为图标题。
surf(double(peaksData)) title(peaksDesc);
读取与 /grid1/
组相关联的 description
属性。将组名指定为 ncreadatt
函数的第二个输入。
g = ncreadatt('example.nc','/grid1/','description')
g = This is a group attribute.
读取全局属性 creation_date
。对于全局属性,将 ncreadatt
的第二个输入参量指定为 '/'
。
creation_date = ncreadatt('example.nc','/','creation_date')
creation_date = 29-Mar-2010
在 NetCDF 文件中查找所有无限维度
此示例说明如何使用高级函数在 NetCDF 文件中查找一个组的所有无限维度。
使用 ncinfo
函数获取示例文件 example.nc
中 /grid2/
组的相关信息。
ginfo = ncinfo('example.nc','/grid2/')
ginfo = Filename: '\\matlabroot\toolbox\matlab\demos\example.nc' Name: 'grid2' Dimensions: [1x3 struct] Variables: [1x1 struct] Attributes: [1x1 struct] Groups: [] Format: 'netcdf4'
ncinfo
返回一个包含组信息的结构体数组。
获取表示该组的无限维度的布尔值的向量。
unlimDims = [ginfo.Dimensions.Unlimited]
unlimDims = 0 0 1
用 unlimDims
向量显示无限维度。
disp(ginfo.Dimensions(unlimDims))
Name: 'time' Length: 0 Unlimited: 1
使用低级函数读取 NetCDF 文件
此示例显示如何使用 netcdf
命名空间中的 MATLAB 低级函数获取有关 netCDF 文件中的维度、变量和属性的信息。要有效使用这些函数,应该熟悉 netCDF C 接口。
打开 NetCDF 文件
使用 netcdf.open
函数,以只读访问权限打开示例 netCDF 文件 example.nc
。
ncid = netcdf.open("example.nc","NC_NOWRITE");
netcdf.open
返回文件标识符。
获取有关 netCDF 文件的信息
使用 netcdf.inq
函数获取有关文件内容的信息。此函数对应于 netCDF 库 C API 中的 nc_inq
函数。
[ndims,nvars,natts,unlimdimID] = netcdf.inq(ncid)
ndims = 3
nvars = 3
natts = 1
unlimdimID = -1
netcdf.inq
返回文件中维度、变量和全局属性的数量,并返回文件中无限维度的标识符。无限维度可以增长。
使用 netcdf.inqAttName
函数获取文件中全局属性的名称。此函数对应于 netCDF 库 C API 中的 nc_inq_attname
函数。要获取属性的名称,必须指定该属性所关联变量的 ID 和属性编号。要访问与特定变量不相关联的全局属性,请使用常量 "NC_GLOBAL"
作为变量 ID。
global_att_name = netcdf.inqAttName(ncid,... netcdf.getConstant("NC_GLOBAL"),0)
global_att_name = 'creation_date'
使用 netcdf.inqAtt
函数获取有关属性的数据类型和长度的信息。此函数对应于 netCDF 库 C API 中的 nc_inq_att
函数。再次使用 netcdf.getConstant("NC_GLOBAL")
指定变量 ID。
[xtype,attlen] = netcdf.inqAtt(ncid,... netcdf.getConstant("NC_GLOBAL"),global_att_name)
xtype = 2
attlen = 11
使用 netcdf.getAtt
函数获取属性值。
global_att_value = netcdf.getAtt(ncid,... netcdf.getConstant("NC_GLOBAL"),global_att_name)
global_att_value = '29-Mar-2010'
使用 netcdf.inqDim
函数获取文件中第一个维度的相关信息。此函数对应于 netCDF 库 C API 中的 nc_inq_dim
函数。netcdf.inqDim
的第二个输入是维度 ID,它是一个标识维度的从 0 开始的索引。第一个维度的索引值为 0
。
[dimname,dimlen] = netcdf.inqDim(ncid,0)
dimname = 'x'
dimlen = 50
netcdf.inqDim
返回维度的名称和长度。
使用 netcdf.inqVar
函数获取文件中第一个变量的相关信息。此函数对应于 netCDF 库 C API 中的 nc_inq_var
函数。netcdf.inqVar
的第二个输入是变量 ID,它是一个标识变量的从 0 开始的索引。第一个变量的索引值为 0
。
[varname,vartype,dimids,natts] = netcdf.inqVar(ncid,0)
varname = 'avagadros_number'
vartype = 6
dimids = []
natts = 1
netcdf.inqVar
返回名称、数据类型、维度 ID 以及与变量相关联的属性的数量。vartype
中返回的数据类型信息是 netCDF 数据类型常量的数值,例如,NC_INT
和 NC_BYTE
。有关这些常量的信息,请参阅 netCDF 文档。
读取 NetCDF 文件中的数据
使用 netcdf.getVar
函数读取示例文件中与变量 avagadros_number
相关联的数据。netcdf.getVar
的第二个输入是变量 ID,它是一个标识变量的从 0 开始的索引。avagadros_number
变量的索引值为 0
。
A_number = netcdf.getVar(ncid,0)
A_number = 6.0221e+23
查看 A_number
的数据类型。
whos A_number
Name Size Bytes Class Attributes A_number 1x1 8 double
netcdf
命名空间中的函数自动选择与 NetCDF 数据类型最匹配的 MATLAB 类,但您也可以使用 netcdf.getVar
的可选参量指定返回数据的类。
读取与 avagadros_number
相关联的数据,并以 single
类返回数据。
A_number = netcdf.getVar(ncid,0,"single")
A_number = single
6.0221e+23
whos A_number
Name Size Bytes Class Attributes A_number 1x1 4 single
关闭 NetCDF 文件
关闭 netCDF 文件 example.nc
。
netcdf.close(ncid)
以交互方式读取 NetCDF 文件中的数据
此示例说明如何使用导入数据任务来浏览 netCDF 文件的结构,从文件中导入数据,然后分析和可视化数据。
下载数据集
美国国家海洋和大气管理局物理科学实验室 (NOAA PSL) 托管由美国国家冰雪数据中心 (NSIDC) 编制的北半球积雪数据的插值数据集。将此数据集下载到您的当前文件夹。
filename = "snowcover.mon.mean.nc"; url = "https://downloads.psl.noaa.gov/Datasets/snowcover/snowcover.mon.mean.nc"; fullLocalPath = websave(filename,url);
浏览和导入数据
通过选择实时编辑器选项卡上的任务 > 导入数据,在实时编辑器中打开导入数据任务。在文件字段中输入 netCDF 数据集的文件名 snowcover.mon.mean.nc
。使用任务浏览数据结构,包括变量及其属性:
全局属性给出文件中包含的数据的一般含义,包括引用。
该数据集包含三个维度:两个空间维度(
lat
和lon
)与一个时间维度 (time
)。lat
变量的大小为 90,具有一个名为units
的属性,其属性值为'degrees_north'
。此变量表示测量点在赤道以北的纬度,以度为单位。lon
变量的大小为 360,具有一个名为units
的属性,其属性值为'degrees_east'
。此变量表示测量点在本初子午线以东的经度,以度为单位。time
变量的大小为 297,具有一个无限维度和一个名为units
的属性,其属性值为'hours since 1800-01-01 00:00:0.0'
。此变量表示进行测量的时间。snowcover
变量的大小为 360×90×297,第三个维度为无限维度,具有一个名为units
的属性(其属性值为'%'
)和一个名为long_name
的属性(其属性值为'Monthly Means Snowcover Extent'
)。snowcover
变量是lat
、lon
和time
这三个变量的联合。它表示北半球特定月份特定点的月平均积雪量,以积雪覆盖地面的百分比来衡量。
从 lat
、lon
、time
和 snowcover
变量中选择并导入数据。
要查看此任务生成的代码,请点击任务参数区域底部的显示代码展开任务显示。
% Create a structure to store imported netCDF data snowcover_mon_mean = struct(); filename = "snowcover.mon.mean.nc"; snowcover_mon_mean.Variables(1).Name = "lat"; snowcover_mon_mean.Variables(2).Name = "lon"; snowcover_mon_mean.Variables(3).Name = "time"; snowcover_mon_mean.Variables(4).Name = "snowcover"; snowcover_mon_mean.Variables(1).Value = ncread(filename, "/lat"); snowcover_mon_mean.Variables(2).Value = ncread(filename, "/lon"); snowcover_mon_mean.Variables(3).Value = ncread(filename, "/time"); snowcover_mon_mean.Variables(4).Value = ncread(filename, "/snowcover"); clear filename
组织和准备数据
为数据集中的每个变量创建局部变量。
lats = snowcover_mon_mean.Variables(1).Value; lons = snowcover_mon_mean.Variables(2).Value; times = snowcover_mon_mean.Variables(3).Value; snows = snowcover_mon_mean.Variables(4).Value;
创建 lats
和 lons
的显示版本,为绘制数据做准备。选择适合在每个轴上显示十个标签的显示比例。
numLabels = 10; latDisps = strings(length(lats),1); latsLabelInterval = length(lats)/numLabels; latLabelInds = latsLabelInterval:latsLabelInterval:length(lats); latDisps(latLabelInds) = lats(latLabelInds); lonDisps = strings(length(lons),1); lonsLabelInterval = length(lons)/numLabels; lonLabelInds = lonsLabelInterval:lonsLabelInterval:length(lons); lonDisps(lonLabelInds) = lons(lonLabelInds);
time
变量的 units
属性表示 time
是从 1800 年开始以小时为单位测量的。此外,snowcover
变量的 long_name
属性指示这些值是月均值。使用这些信息将 times
向量转换为对应的 datetime
值,并创建 times
的显示版本,该版本包含月份和年份,但不显示日期。
sampTimes = datetime("1800-01-01 00:00:00") + hours(times); sampTimes.Format = "MMM-yyyy"; sampTimeDisps = string(sampTimes);
snows
的第一个维度表示纬度,第二个维度表示经度。要创建此数据的热图,第一个维度应对应于一列(经度),第二个维度应对应于一行(纬度)。置换 snows
的这两个维度。
snows = permute(snows,[2 1 3]);
对数据绘图
为第一个月的数据创建热图。
h = heatmap(lons,lats,snows(:,:,1)); h.XLabel = "Longitude (°E)"; h.YLabel = "Latitude (°N)"; h.XDisplayLabels = lonDisps; h.YDisplayLabels = latDisps; h.Colormap = winter; h.GridVisible = "off";
通过遍历所有可用时间的数据为热图添加动画效果。
for i = 1:numel(sampTimeDisps) h.ColorData = snows(:,:,i); h.Title = "Percent Snow Cover vs. Location (" + sampTimeDisps(i) + ")"; pause(0.1) end
找到积雪量最大的时间
计算并绘制总积雪量与时间的函数关系图。
cumSnowsbyTime = squeeze(sum(snows,[1 2])) / (length(lats)*length(lons)); plot(sampTimes,cumSnowsbyTime) xlabel("Date") ylabel("Total Snow Cover (%)") title("Total Snow Cover vs. Date")
找出并绘制积雪量最大的时间。
[maxSnowsbyTime,maxSnowsbyTimeInd] = max(cumSnowsbyTime); h = heatmap(lons,lats,snows(:,:,maxSnowsbyTimeInd)); h.XLabel = "Longitude (°E)"; h.YLabel = "Latitude (°N)"; h.Title = "Percent Snow Cover vs. Location (" + sampTimeDisps(maxSnowsbyTimeInd) + ")"; h.XDisplayLabels = lonDisps; h.YDisplayLabels = latDisps; h.Colormap = winter; h.GridVisible = "off";
积雪量最大的月份是 1978 年 2 月。
找到积雪量最大的位置
计算并绘制平均积雪量与位置的函数关系图。
cumSnowsbyLoc = sum(snows,3) / length(times); h = heatmap(lons,lats,cumSnowsbyLoc); h.XLabel = "Longitude (°E)"; h.YLabel = "Latitude (°N)"; h.Title = "Average Percent Snow Cover vs. Location"; h.XDisplayLabels = lonDisps; h.YDisplayLabels = latDisps; h.Colormap = winter; h.GridVisible = "off";
找到并绘制积雪量最大的位置。
maxSnowsbyLocVal = max(cumSnowsbyLoc,[],"all"); maxSnowsbyLoc = maxSnowsbyLocVal*(cumSnowsbyLoc == maxSnowsbyLocVal); h = heatmap(lons,lats,maxSnowsbyLoc); h.XLabel = "Longitude (°E)"; h.YLabel = "Latitude (°N)"; h.Title = "Locations of Maximum Snow Cover"; h.XDisplayLabels = lonDisps; h.YDisplayLabels = latDisps; h.Colormap = winter; h.GridVisible = "off";
积雪量最大的地方包括格陵兰岛的大部分、斯瓦尔巴特群岛和弗朗茨约瑟夫地的部分地区。
感谢
NH Ease-Grid 积雪数据由美国科罗拉多州博尔德市的 NOAA PSL 在其网站 https://psl.noaa.gov
上提供。