【问题标题】:Merging multiple observational nc files based on station attributes根据台站属性合并多个观测 nc 文件
【发布时间】:2022-08-16 05:31:00
【问题描述】:

我正在尝试合并多个 nc 文件,这些文件包含不同纬度和经度的不同深度的物理海洋学数据。 我正在使用 ds = xr.open_mfdataset 来执行此操作,但是文件没有正确合并,当我尝试绘制它们时,似乎合并文件只有一个结果值。 这是我正在使用的代码:

##Combining using concat_dim and nested method
ds = xr.open_mfdataset(\"33HQ20150809*.nc\", concat_dim=[\'latitude\'], combine= \"nested\")
ds.to_netcdf(\'geotraces2015_combined.nc\')
df = xr.open_dataset(\"geotraces2015_combined.nc\")

##Setting up values. Oxygen values are transposed so it matches same shape as lat and pressure. 
oxygen = df[\'oxygen\'].values.transpose()
##Plotting using colourf
fig = plt.figure()
ax = fig.add_subplot(111)
plt.contourf(oxygen, cmap = \'inferno\')
plt.gca().invert_yaxis()
cbar = plt.colorbar(label = \'Oxygen Concentration (umol kg-1\')

您可以在 CTD 下从此处下载 nc 文件 https://cchdo.ucsd.edu/cruise/33HQ20150809

这是每个文件的样子:

<xarray.Dataset>
Dimensions:         (pressure: 744, time: 1, latitude: 1, longitude: 1)
Coordinates:
  * pressure        (pressure) float64 0.0 1.0 2.0 3.0 ... 741.0 742.0 743.0
  * time            (time) datetime64[ns] 2015-08-12T18:13:00
  * latitude        (latitude) float32 60.25
  * longitude       (longitude) float32 -179.1
Data variables: (12/19)
    pressure_QC     (pressure) int16 ...
    temperature     (pressure) float64 ...
    temperature_QC  (pressure) int16 ...
    salinity        (pressure) float64 ...
    salinity_QC     (pressure) int16 ...
    oxygen          (pressure) float64 ...
    ...              ...
    CTDNOBS         (pressure) float64 ...
    CTDETIME        (pressure) float64 ...
    woce_date       (time) int32 ...
    woce_time       (time) int16 ...
    station         |S40 ...
    cast            |S40 ...
Attributes:
    EXPOCODE:                   33HQ20150809
    Conventions:                COARDS/WOCE
    WOCE_VERSION:               3.0
...

另一个文件如下所示:

<xarray.Dataset>
Dimensions:         (pressure: 179, time: 1, latitude: 1, longitude: 1)
Coordinates:
  * pressure        (pressure) float64 0.0 1.0 2.0 3.0 ... 176.0 177.0 178.0
  * time            (time) datetime64[ns] 2015-08-18T19:18:00
  * latitude        (latitude) float32 73.99
  * longitude       (longitude) float32 -168.8
Data variables: (12/19)
    pressure_QC     (pressure) int16 ...
    temperature     (pressure) float64 ...
    temperature_QC  (pressure) int16 ...
    salinity        (pressure) float64 ...
    salinity_QC     (pressure) int16 ...
    oxygen          (pressure) float64 ...
    ...              ...
    CTDNOBS         (pressure) float64 ...
    CTDETIME        (pressure) float64 ...
    woce_date       (time) int32 ...
    woce_time       (time) int16 ...
    station         |S40 ...
    cast            |S40 ...
Attributes:
    EXPOCODE:                   33HQ20150809
    Conventions:                COARDS/WOCE
    WOCE_VERSION:               3.0

编辑:这是我仍然不起作用的新方法: 我正在尝试按照 Michael 的方法使用预处理来 set_coords、squeeze 和 expand_dims:

def preprocess(ds):
return ds.set_coords(\'station\').squeeze([\"latitude\", \"longitude\", \"time\"]).expand_dims(\'station\')
ds = xr.open_mfdataset(\'33HQ20150809*.nc\', concat_dim=\'station\', combine=\'nested\', preprocess=preprocess)

但是我还是有同样的问题...

  • 您可以使用xr.open_dataset 逐个打开文件并检查它们是否沿除纬度以外的所有维度对齐,xr.align(list_of_datasets, join=\'exact\', exclude=\'latitude\')?在不知道数据前后的样子的情况下很难调试合并:/
  • 哦 - 如果您的数据需要在纬度和经度中加入,要么显式提供带有嵌套列表的结构,要么使用 combine=\'by_coords\' 并跳过 concat dim 参数
  • 如果我使用 combine=\'by_coords\' 它会使内核崩溃。数据集包含 4 个坐标,但我希望合并在纬度和压力上,但它也不允许我这样做。
  • 有 106 个文件要合并,所以我只尝试了四个。 When I do the \"list_of_datasets\",ds1 = xr.open_dataset(\'33HQ20150809_00001_00002_ctd.nc\') ds2 = xr.open_dataset(\'33HQ20150809_00001_00005_ctd.nc\') ds3 = xr.open_dataset(\'33HQ20150809_00001_00007_ctd.nc\ ') ds4 = xr.open_dataset(\'33HQ20150809_00002_00004_ctd.nc\') list_of_datasets = (ds1, ds2, ds3, ds4) xr.align(list_of_datasets, join=\'exact\', exclude=\'latitude\') 我得到 AttributeError: \'tuple\' 对象没有属性 \'copy\'
  • 哦,对不起 - 应该是 xr.align(*list_of_datasets, ...) 并带有星号以将列表扩展为位置参数

标签: python matplotlib python-xarray netcdf4


【解决方案1】:

xarray 数据模型要求所有数据维度垂直且完整。换句话说,沿每个维度的每个坐标的每个组合都将出现在数据数组中(作为数据或 NaN)。

您可以使用 xarray 处理观测数据,例如您的数据,但您必须小心索引以确保不会爆炸数据维度。具体来说,当数据不是真正的数据维度,而只是与台站或监视器相关的观察或属性时,您应该将其更多地视为数据变量而不是坐标。在您的情况下,您的维度似乎是站 ID 和压力水平(没有每个站的完整观察集,而是数据的一个维度)。另一方面,时间、纬度和经度是每个站点的属性,不应被视为维度。

我将生成一些看起来像你的随机数据:

def generate_random_station():
    station_id = "{:09d}".format(np.random.randint(0, int(1e9)))
    time = np.random.choice(pd.date_range("2015-08-01", "2015-08-31", freq="H"))
    plevs = np.arange(np.random.randint(1, 1000)).astype(float)
    lat = np.random.random() * 10 + 30
    lon = np.random.random() * 10 - 80

    ds = xr.Dataset(
        {
            "salinity": (('pressure', ), np.sin(plevs / 200 + lat)),
            "woce_date": (("time", ), [time]),
            "station": station_id,
        },
        coords={
            "pressure": plevs,
            "time": [time],
            "latitude": [lat],
            "longitude": [lon],
        },
    )

    return ds

这最终看起来如下所示:

In [11]: single = generate_random_station()

In [12]: single
Out[12]:
<xarray.Dataset>
Dimensions:    (pressure: 37, time: 1, latitude: 1, longitude: 1)
Coordinates:
  * pressure   (pressure) float64 0.0 1.0 2.0 3.0 4.0 ... 33.0 34.0 35.0 36.0
  * time       (time) datetime64[ns] 2015-08-21T01:00:00
  * latitude   (latitude) float64 39.61
  * longitude  (longitude) float64 -72.19
Data variables:
    salinity   (pressure) float64 0.9427 0.941 0.9393 ... 0.8726 0.8702 0.8677
    woce_date  (time) datetime64[ns] 2015-08-21T01:00:00
    station    <U9 '233136181'

问题是纬度、经度和时间坐标并不是可用于索引更大数组的真正维度。它们的间距不均匀,并且纬度/经度/时间的每个组合都没有一个站点。因此,我们需要格外小心,以确保在合并数据时,不会扩展 lat/lon/time 维度。

为此,我们将压缩这些维度,并沿新维度station 扩展数据集:

In [13]: single.set_coords('station').squeeze(["latitude", "longitude", "time"]).expand_dims('station')
Out[13]:
<xarray.Dataset>
Dimensions:    (pressure: 37, station: 1)
Coordinates:
  * station    (station) <U9 '233136181'
  * pressure   (pressure) float64 0.0 1.0 2.0 3.0 4.0 ... 33.0 34.0 35.0 36.0
    time       datetime64[ns] 2015-08-21T01:00:00
    latitude   float64 39.61
    longitude  float64 -72.19
Data variables:
    salinity   (station, pressure) float64 0.9427 0.941 0.9393 ... 0.8702 0.8677
    woce_date  (station) datetime64[ns] 2015-08-21T01:00:00

这可以对您的所有数据集进行,然后它们可以沿着“站”维度连接:

In [14]: all_stations = xr.concat(
   ...:     [
   ...:         generate_random_station()
   ...:         .set_coords('station')
   ...:         .squeeze(["latitude", "longitude", "time"])
   ...:         .expand_dims('station')
   ...:         for i in range(10)
   ...:     ],
   ...:     dim="station",
   ...: )

这会产生一个按压力水平和站点索引的数据集:

In [15]: all_stations
Out[15]:
<xarray.Dataset>
Dimensions:    (pressure: 657, station: 10)
Coordinates:
  * pressure   (pressure) float64 0.0 1.0 2.0 3.0 ... 653.0 654.0 655.0 656.0
  * station    (station) <U9 '197171488' '089978445' ... '107555081' '597650083'
    time       (station) datetime64[ns] 2015-08-19T06:00:00 ... 2015-08-24T15...
    latitude   (station) float64 37.96 34.3 38.74 39.28 ... 37.72 33.89 36.46
    longitude  (station) float64 -74.28 -73.59 -78.33 ... -76.6 -76.47 -77.96
Data variables:
    salinity   (station, pressure) float64 0.2593 0.2642 0.269 ... 0.8916 0.8893
    woce_date  (station) datetime64[ns] 2015-08-19T06:00:00 ... 2015-08-24T15...

您现在可以沿纬度和压力水平维度绘制:

In [16]: all_stations.salinity.plot.contourf(x="latitude", y="pressure")

【讨论】:

  • 我尝试将此代码 import os import glob folder = "/Users/mariacristinaalvarez/Documents/Documents/Projects/GEOTRACES2015" 应用于 glob.glob(os.path.join(folder,'*.nc')) 中的文件名:data = xr.open_dataset(filename) all_sttions = xr.concat([data.set_coords('station').squeeze(["latitude", "longitude", "time"]).expand_dims('station')], dim=' station'),但生成的数据集仅包含来自 106 个文件中的一个文件的数据
猜你喜欢
  • 2014-03-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-18
  • 2018-12-05
  • 1970-01-01
  • 1970-01-01
  • 2012-06-23
相关资源
最近更新 更多