首页 / 资讯中心 / 文章详情

NetCDF海洋数据入门:从读取到绘制全球海水温度与海冰浓度图

NetCDF海洋数据入门:从读取到绘制全球海水温度与海冰浓度图 ★ FEATURED ARTICLE
简介这份资源面向气象、海洋与气候方向的初学者及科研入门者提供来自Met Office Hadley Centre观测数据集的全球海表温度与海冰浓度数据并配套一段入门级Python处理代码帮助读者快速了解nc文件的变量结构与数据组织方式解决拿到原始观测数据后不知从何下手的常见问题。压缩包共3个文件以2个nc格式数据文件和1个py脚本为主前者分别承载海表温度与海冰浓度场后者用于读取并查看变量情况整体约167.98MB。目前已有4933人学习下载说明其在气候数据入门场景中具备一定参考价值。读者可借助脚本直接跑通数据读取流程观察变量维度、时间范围与缺测值处理方式并在此基础上开展自己的分析与绘图练习适合作为熟悉HadISST类数据的第一份练手材料。1. 从一份“看不懂”的数据集说起海水温度和海冰浓度到底是什么你有没有过这种经历下载了一个压缩包解压后看到一堆.nc文件双击打不开用记事本打开全是乱码心里第一反应是“这玩意儿我是不是搞不定”我第一次接触海洋数据的时候就是这样文件名里带着年份和变量缩写打开一看全是数字矩阵完全不知道从哪下手。其实这份“全球海水表面温度和海冰浓度数据集2020a专用”没那么玄乎你可以把它理解成一张覆盖整个地球海洋的“体温表”加“冰层厚度记录表”——海水表面温度告诉你哪片海热、哪片海冷海冰浓度告诉你极地附近有多少比例的海面被冰盖住。它适合谁适合刚接触气候、海洋、环境方向数据的学生也适合想拿真实地球数据练手的数据分析新手。你不需要先成为海洋学家只需要会一点点 Python 和一颗不怕看到乱码的心就能把这份数据读出人话。2. 为什么值得从这份数据入手它把“真实世界”塞进了一个文件2.1 它不像练习数据那样“干净得假”很多入门教程给你的 CSV 是精心修剪过的没有缺失值、没有奇怪的单位、没有地理坐标的坑。但真实的地球观测数据不是这样。这份数据集里海水表面温度通常以摄氏度记录海冰浓度以 0 到 1 之间的小数或百分比表示空间上按经纬度网格排列时间上按天或按月组织。你拿到它第一件事不是画图而是搞清楚“哪个维度是时间、哪个是纬度、哪个是经度、缺测值用什么数字代替”。这听起来麻烦但恰恰是这种麻烦让你第一次真正理解“数据清洗”四个字不是课本上的名词而是你打开文件后必须面对的现实。入门阶段最怕的就是一直练假数据一碰真数据就翻车而这份数据正好帮你提前把坑踩一遍。2.2 它让你第一次把“代码”和“地球”连起来你写一行代码读出一个数字这个数字对应的是太平洋某处海面下几厘米的温度你画一张图看到的是整个大洋的温度分布。这种“代码直接作用于真实世界”的反馈是练习数据集给不了的。而且海水表面温度和海冰浓度天然相关——温度高的地方冰少温度低的地方冰多你可以在同一个文件里同时看到两个变量顺手就能做一次相关性观察。对于零基础的人来说这种“一个动作看到两个结果”的体验比啃十页理论都管用。入门的话建议先别想着做预测模型先把“读出来、画出来、看懂图”这三步走完信心就建立起来了。2.3 它帮你建立“网格数据”的直觉你平时接触的表格是一行一条记录但这份数据是网格化的每个经纬度格子对应一个温度值时间再叠加上去就变成一个三维甚至四维的数组。很多新手第一次看到(time, lat, lon)这样的维度顺序会发怵其实你可以把它想成一摞地图每一页是一个时间点页面上每个像素点是一个经纬度格子格子里填着温度。你翻页就是在看时间变化盯着一个像素看就是在看某个地点的时间序列。这种直觉一旦建立后面再遇到任何气象、海洋、遥感数据你都不会慌。这份数据集就是用来练这个直觉的它不要求你懂流体力学只要求你愿意把“一摞地图”这个画面记住。3. 新手第一步把文件读进来先别管画图3.1 先认清你手里的是什么格式这份数据集常见的存储格式是 NetCDF扩展名一般是.nc。你可以把它理解成一个“带标签的盒子”盒子里装着多个变量比如温度、冰浓度每个变量有自己的名字、单位、维度顺序和缺测值标记。你不需要记住 NetCDF 的底层规范只需要知道两件事第一用 Python 的xarray库可以像打开一个字典一样打开它第二打开之后先看“里面有什么”而不是急着取数。我第一次学的时候就是直接print整个数据集结果刷屏几百行完全找不到重点。正确的做法是先看变量列表和维度信息再决定取哪个变量。3.2 装好两个库跑通第一段读取代码入门阶段你只需要两个库xarray负责读 NetCDFmatplotlib负责画图。如果你用的是 Anaconda这两个通常已经自带如果没有用 pip 装一下即可。下面这段代码的作用是打开文件、打印数据集结构、取出海水表面温度变量并查看它的维度。注意把文件路径换成你解压后的实际路径文件名不要照抄看你自己的文件夹里叫什么。import xarray as xr # 打开 NetCDF 文件decode_timesTrue 让时间自动转成可读日期 ds xr.open_dataset(你的路径/你的文件名.nc, decode_timesTrue) # 先看整体结构有哪些变量、每个变量的维度是什么 print(ds) # 取出海水表面温度变量变量名以文件内实际为准常见如 sst 或 sea_surface_temperature sst ds[sst] # 看这个变量的维度顺序和形状 print(sst.dims) print(sst.shape) # 看前 5 个时间点确认时间轴是否正常 print(sst.time.values[:5])这段代码里xr.open_dataset是入口它不会把整个文件读进内存而是先建立一个“索引”所以你打开大文件也不会立刻卡死。print(ds)输出的是数据集的“目录”你会看到Dimensions、Coordinates、Data variables三块分别告诉你维度大小、坐标轴信息和变量清单。sst.dims告诉你这个变量的维度顺序常见是(time, lat, lon)意思是第一维是时间、第二维是纬度、第三维是经度。sst.shape给出每个维度有多少个格子比如(365, 180, 360)就代表一年每天一张 180×360 的网格图。sst.time.values[:5]是确认时间轴有没有被正确解析如果输出的是datetime64类型说明没问题如果输出的是奇怪的数字可能需要检查decode_times参数或文件本身的时间单位。3.3 取一个时间点、一个地点把数字变成人话读完结构之后下一步是“取一个具体值”这是建立信心最快的方式。你不需要一上来就画全球图先取某一天、某个经纬度的温度看看它是不是一个合理的数字比如海水温度在 -2 到 35 摄氏度之间海冰浓度在 0 到 1 之间。下面这段代码取第一个时间点、纬度 0 度、经度 0 度附近的值并打印出来。注意sel是按标签取值isel是按位置取值新手先用isel更不容易出错。# 取第一个时间点、纬度索引 90、经度索引 180 的位置具体索引对应哪经纬度要看坐标值 one_value sst.isel(time0, lat90, lon180).values print(取到的温度值, one_value) # 同时看一下这个位置的经纬度坐标确认你取的是哪里 print(纬度, sst.lat.values[90]) print(经度, sst.lon.values[180])这里isel里的time0表示第一个时间层lat90和lon180是数组下标不是经纬度数值。你打印出来的经纬度坐标才是真实位置。如果取到的值是一个很大的负数比如 -999 或 9.969e36那通常是缺测值标记说明这个格子是陆地或者没有观测。入门阶段遇到缺测值不要慌先记下它的数值后面画图时用where把它屏蔽掉就行。这一步的目的不是分析而是让你亲眼看到“代码里的一个下标”对应“地球上的一个点”这个连接一旦建立后面就不会觉得数据是虚的。4. 把一摞地图画出来第一张全球分布图怎么调4.1 画图前先处理缺测值和单位直接sst.isel(time0).plot()通常能出一张图但新手最容易翻车的地方是缺测值把色标拉爆整张图变成一片深色什么都看不清。原因是缺测值被当成一个极大的数参与配色。解决办法是在画图前用where把超过合理范围的值设为 NaN或者用xarray的plot参数里指定vmin和vmax。另外海水表面温度的单位常见是摄氏度但有些文件存的是开尔文数值会在 270 到 310 之间如果你看到这种数减 273.15 就换回摄氏度了。海冰浓度如果是 0 到 1 的小数画图时可以直接用如果想显示百分比就乘 100。这些判断不需要背打开文件后看一眼数值范围就能猜个八九不离十。4.2 一段可复现的画图代码下面这段代码取第一个时间点的海水表面温度屏蔽掉明显不合理的值画一张全球分布图并加上颜色条和标题。figsize控制图的大小cmap选coolwarm是因为温度有正有负冷暖色对比直观如果你画海冰浓度可以换成Blues或viridis。vmin和vmax根据你数据的实际范围调先打印一下sst.min()和sst.max()再定不要照抄。import matplotlib.pyplot as plt # 取第一个时间点并把超出合理范围的值设为 NaN按你数据的实际范围调整 sst_day sst.isel(time0).where((sst.isel(time0) -5) (sst.isel(time0) 40)) # 画图figsize 控制大小cmap 选冷暖色vmin/vmax 固定色标范围 sst_day.plot(figsize(10, 5), cmapcoolwarm, vmin-2, vmax32) # 加标题和颜色条标签 plt.title(海水表面温度分布第一个时间点) plt.xlabel(经度) plt.ylabel(纬度) plt.show()这段代码里.where(...)的作用是“只保留条件为真的格子其余变成 NaN”这样缺测值和陆地就不会干扰配色。figsize(10, 5)是宽 10 高 5 英寸新手可以先按这个比例来觉得扁就调高一点。cmapcoolwarm是红蓝渐变温度高的地方偏红、低的地方偏蓝符合直觉。vmin和vmax一定要根据你打印出来的最小最大值来定如果你设得太窄极端值会被截断设得太宽中间变化就看不出来。画完这张图你应该能看到赤道附近偏暖、高纬度偏冷的整体格局如果看到大片空白或整片同色回去检查缺测值处理和vmin/vmax设置。4.3 把海冰浓度叠在同一张图上观察海冰浓度和海水温度是两份数据但你可以用两个子图并排看或者用同一张图的两个图层。新手建议先并排画避免颜色混淆。下面这段代码用subplots画两个子图左边温度、右边冰浓度共享经纬度范围。注意冰浓度的变量名以文件内实际为准常见如siconc或sea_ice_fraction不要照抄。fig, axes plt.subplots(1, 2, figsize(14, 5)) # 左图海水表面温度 sst.isel(time0).where((sst.isel(time0) -5) (sst.isel(time0) 40)).plot( axaxes[0], cmapcoolwarm, vmin-2, vmax32 ) axes[0].set_title(海水表面温度) # 右图海冰浓度变量名按实际文件改 ice ds[siconc] # 如果报错先 print(ds) 看变量清单 ice.isel(time0).plot(axaxes[1], cmapBlues, vmin0, vmax1) axes[1].set_title(海冰浓度) plt.tight_layout() plt.show()这里subplots(1, 2)表示一行两列axes[0]和axes[1]分别对应左右子图。tight_layout()是自动调整间距防止标题和坐标轴标签重叠。画完之后你会看到温度高的区域冰浓度低、温度低的区域冰浓度高这个直观对比就是这份数据集最友好的地方——它让你不用任何统计检验就能感受到两个变量的关系。入门阶段做到这一步你已经完成了“读取、取点、画图、对比”的完整闭环接下来可以尝试换一个时间点、换一个季节看看图怎么变。5. 避坑指南新手最容易翻车的五个地方5.1 现象打开文件报错“找不到变量名”原因变量名和你想的不一样解决先打印清单再取数很多新手看到教程里写ds[sst]就照抄结果自己文件里变量叫sea_surface_temperature或者带前缀后缀直接报KeyError。这不是你代码写错了而是每个数据集的变量命名不统一。正确的做法是打开文件后先print(ds.data_vars)或print(ds)把变量清单看一遍再决定取哪个名字。如果你不确定哪个是温度可以看变量的long_name或units属性通常会有说明。记住变量名以你手里的文件为准教程里的名字只是示例。5.2 现象画出来的图一片深色或一片空白原因缺测值没处理或色标范围不对解决先看数值范围再定 vmin/vmax缺测值在 NetCDF 里通常是一个很大的数比如9.969e36或者一个特定标记比如-999。如果你直接画图这个极值会把色标拉到它那里导致正常数据全挤在一个颜色里。解决办法分两步先用sst.min()和sst.max()看数值范围再用.where()把超出合理范围的值设为 NaN最后在plot里固定vmin和vmax。另外陆地格子通常也是缺测画出来是空白这是正常的不是你的图坏了。5.3 现象时间轴是一串看不懂的数字原因时间单位没有解码解决检查 decode_times 和文件的时间属性有些文件的时间存储为“从某个起点开始的小时数”或“天数”如果你看到time的值是 0、1、2 这样的整数说明没有解码成日期。xr.open_dataset默认会尝试解码但有些文件需要手动指定decode_timesTrue或者用xr.decode_cf()。如果还是不行可以打印ds.time.attrs看它的units属性里面会写类似“hours since 2020-01-01”的信息根据这个手动换算。入门阶段遇到时间轴问题不用深究先确认你能按索引取到不同时间层画图不受影响日期显示可以后面再修。5.4 现象内存爆了或者读取特别慢原因一次性读了太多时间层解决用 isel 只取需要的切片整份数据集可能包含几十年、每天多个时间层如果你直接ds[sst].values把全部数据转成数组内存很容易撑爆。正确的习惯是“用什么取什么”画某一天就isel(time0)画某个月就取对应索引不要一次性全读。xarray的好处是延迟加载你打开文件时并没有真正读数据只有在你取值或画图时才读那一部分。所以尽量在isel或sel之后再加.values或.plot()而不是先转数组再切片。5.5 现象经纬度顺序和想象中相反原因不同文件的维度顺序不统一解决先看 dims 再决定切片顺序有的文件维度是(time, lat, lon)有的是(time, lon, lat)还有的纬度是从北到南递减。如果你按固定顺序切片可能取到的是另一个位置。解决办法很简单打开文件后先print(sst.dims)看清楚顺序再写isel。如果纬度是递减的画图时图会上下颠倒可以用sortby(lat)重新排序。这个坑不致命但会让你取错点、画反图所以养成“先看 dims 再动手”的习惯能省很多来回调试的时间。6. 下一步学什么从“能画图”到“能回答一个小问题”走到这里你已经能打开文件、取点、画全球图、并排看两个变量了。接下来不建议你去啃气候动力学教材而是给自己提一个很小的问题用这份数据回答它。比如“北半球夏季和冬季的海冰浓度范围差多少”或者“赤道附近的海水温度一年内波动大不大”这种问题不需要高深方法只需要你按时间索引取几个切片、算个平均值、画个折线图。下面这张表是我建议的下一步学习顺序按“够用”原则排的不用全学挑你当前问题需要的用。下一步要用的能力具体做什么大概花多久按时间取切片用isel(timeslice(...))取一段日期半小时算区域平均用.mean(dim[lat,lon])算全球或某区域平均半小时画时间序列把区域平均结果用plot()画折线半小时处理季节差异按月份分组求平均对比冬夏一到两小时简单相关观察把温度和冰浓度在同一个区域做散点或相关系数一到两小时入门的话建议先只做前两行把“取一段时间、算个平均、画条线”跑通你就已经能回答“某片海域温度怎么变”这种问题了。我第一次学的时候贪多想把所有变量所有年份都处理一遍结果代码越写越长、报错越来越多最后连最初那张图都画不出来了。从那以后我每次碰新数据集都强制自己先只取一个时间点、一个变量、画一张图确认这条最小路径跑通再往上加东西。这个习惯帮我省了很多后悔药。希望这份入门路径能帮你把第一张图顺利画出来后面的问题一个一个来就好。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?
咨询建站