关键词:xarray、布尔索引、isel、sel、WRF、NetCDF
“我用
t["bottom_top"==10],结果只给我第 0 层!” “同事写t[t.bottom_top == 10]却对了,为什么?”
如果你也踩过这个坑,本文 3 分钟带你彻底搞懂两种写法的底层差异,并且告诉你 100% 不翻车的人话代码姿势。
在 WRF 输出里,变量往往长这样:
维度名 | 维度大小 | 对应坐标值示例 |
|---|---|---|
bottom_top | 50 | [0,1,2,…,49] |
south_north | 399 | [0,1,2,…,398] |
west_east | 399 | [0,1,2,…,398] |
这就引出了 xarray 的两大索引神器:
.isel() 👉 按位置挑(0,1,2…).sel() 👉 按坐标值挑(500 hPa、300 K …)import wrf
from netCDF4 import Dataset
import numpy as np
# 读取WRF输出文件
ncfile = Dataset("/home/mw/input/typhoon9537/wrfout_d01_2019-08-08_21_00_00")
t = wrf.getvar(ncfile, "geopt")
print(t["bottom_top" == 10])
<xarray.DataArray 'geopt' (south_north: 437, west_east: 447)> Size: 781kB
array([[ 297.94574, 297.95032, 297.95502, ..., 297.31592, 297.32748,
297.33725],
[ 297.9619 , 297.9566 , 297.9591 , ..., 297.3156 , 297.32834,
297.34317],
[ 297.9829 , 297.97464, 297.977 , ..., 297.30307, 297.32504,
297.34854],
...,
[ 589.9714 , 588.9075 , 594.30023, ..., 917.3824 , 3730.8438 ,
5823.588 ],
[ 599.7317 , 594.98584, 593.2099 , ..., 723.3495 , 3845.3953 ,
7601.162 ],
[ 605.5571 , 598.3236 , 595.8047 , ..., 1372.5894 , 4351.075 ,
7479.141 ]], dtype=float32)
Coordinates:
XLONG (south_north, west_east) float32 781kB 116.5 116.6 ... 130.2 130.3
XLAT (south_north, west_east) float32 781kB 20.89 20.89 ... 32.78 32.78
XTIME float32 4B 180.0
Time datetime64[ns] 8B 2019-08-08T21:00:00
Dimensions without coordinates: south_north, west_east
Attributes:
FieldType: 104
MemoryOrder: XYZ
description: geopotential (mass grid)
units: m2 s-2
stagger:
coordinates: XLONG XLAT XTIME
projection: LambertConformal(stand_lon=123.0, moad_cen_lat=27.0, truela...
显而易见这是地面
print(t[t.bottom_top == 10])
<xarray.DataArray 'geopt' (bottom_top: 1, south_north: 437, west_east: 447)> Size: 781kB
array([[[24239.277, 24238.93 , 24238.652, ..., 24186.63 , 24187.566,
24188.516],
[24240.496, 24239.41 , 24239.123, ..., 24189.352, 24189.203,
24187.947],
[24241.709, 24240.562, 24240.242, ..., 24190.338, 24189.453,
24187.465],
...,
[24531.191, 24527.793, 24529.902, ..., 24773.049, 27004.61 ,
28650.615],
[24538.715, 24533.61 , 24531.025, ..., 24620.797, 27095.18 ,
30048.27 ],
[24542.977, 24537.174, 24535.254, ..., 25141.594, 27493.195,
29953.043]]], dtype=float32)
Coordinates:
XLONG (south_north, west_east) float32 781kB 116.5 116.6 ... 130.2 130.3
XLAT (south_north, west_east) float32 781kB 20.89 20.89 ... 32.78 32.78
XTIME float32 4B 180.0
Time datetime64[ns] 8B 2019-08-08T21:00:00
Dimensions without coordinates: bottom_top, south_north, west_east
Attributes:
FieldType: 104
MemoryOrder: XYZ
description: geopotential (mass grid)
units: m2 s-2
stagger:
coordinates: XLONG XLAT XTIME
projection: LambertConformal(stand_lon=123.0, moad_cen_lat=27.0, truela...
高度正确
代码 | xarray 真正做的事 | 结果场景 |
|---|---|---|
t["bottom_top"==10] | 等价于 t[False](字符串恒不成立) | 返回默认0层 |
t[t["bottom_top"] == 10] | 布尔索引:先把坐标值和10比较,用掩码过滤数据 | 若坐标无10 → 🈳 |
t[t.bottom_top == 10] | 语法糖 → t.sel(bottom_top=10) | ✅ 拿坐标值10 |
t.sel(bottom_top=10) | 显式按值选 | ✅ 同上 |
t.isel(bottom_top=10) | 显式按第10个位置选(第11层) | ✅ 从不翻车 |
import xarray as xr, numpy as np
print(t.isel(bottom_top=10))
<xarray.DataArray 'geopt' (south_north: 437, west_east: 447)> Size: 781kB
array([[24239.277, 24238.93 , 24238.652, ..., 24186.63 , 24187.566,
24188.516],
[24240.496, 24239.41 , 24239.123, ..., 24189.352, 24189.203,
24187.947],
[24241.709, 24240.562, 24240.242, ..., 24190.338, 24189.453,
24187.465],
...,
[24531.191, 24527.793, 24529.902, ..., 24773.049, 27004.61 ,
28650.615],
[24538.715, 24533.61 , 24531.025, ..., 24620.797, 27095.18 ,
30048.27 ],
[24542.977, 24537.174, 24535.254, ..., 25141.594, 27493.195,
29953.043]], dtype=float32)
Coordinates:
XLONG (south_north, west_east) float32 781kB 116.5 116.6 ... 130.2 130.3
XLAT (south_north, west_east) float32 781kB 20.89 20.89 ... 32.78 32.78
XTIME float32 4B 180.0
Time datetime64[ns] 8B 2019-08-08T21:00:00
Dimensions without coordinates: south_north, west_east
Attributes:
FieldType: 104
MemoryOrder: XYZ
description: geopotential (mass grid)
units: m2 s-2
stagger:
coordinates: XLONG XLAT XTIME
projection: LambertConformal(stand_lon=123.0, moad_cen_lat=27.0, truela...
print("拿坐标值 10 的那一层:")
print(t.sel(bottom_top=10))
拿坐标值 10 的那一层:
<xarray.DataArray 'geopt' (south_north: 437, west_east: 447)> Size: 781kB
array([[24239.277, 24238.93 , 24238.652, ..., 24186.63 , 24187.566,
24188.516],
[24240.496, 24239.41 , 24239.123, ..., 24189.352, 24189.203,
24187.947],
[24241.709, 24240.562, 24240.242, ..., 24190.338, 24189.453,
24187.465],
...,
[24531.191, 24527.793, 24529.902, ..., 24773.049, 27004.61 ,
28650.615],
[24538.715, 24533.61 , 24531.025, ..., 24620.797, 27095.18 ,
30048.27 ],
[24542.977, 24537.174, 24535.254, ..., 25141.594, 27493.195,
29953.043]], dtype=float32)
Coordinates:
XLONG (south_north, west_east) float32 781kB 116.5 116.6 ... 130.2 130.3
XLAT (south_north, west_east) float32 781kB 20.89 20.89 ... 32.78 32.78
XTIME float32 4B 180.0
Time datetime64[ns] 8B 2019-08-08T21:00:00
Dimensions without coordinates: south_north, west_east
Attributes:
FieldType: 104
MemoryOrder: XYZ
description: geopotential (mass grid)
units: m2 s-2
stagger:
coordinates: XLONG XLAT XTIME
projection: LambertConformal(stand_lon=123.0, moad_cen_lat=27.0, truela...
.isel
t.isel(bottom_top=0) 永远是第一层,不看坐标是什么。.sel
t.sel(bottom_top=10)、t.sel(pressure=500, method='nearest')[] 里手写比较式
把 .isel / .sel 拼出来,代码可读直接拉满。xarray 不看你写成 == 还是什么,它只看上下文:
坐标-值映射时用 .sel;位置编号时用 .isel。
记住这一条,索引永不迷路!🎉
如果喜欢这样的科普,顺手点个赞吧!更多 xarray 小技巧,评论区见~