繁体   English   中英

plot雨季开始的第一天具体情况如何用.netcdf数据查询某地区?

[英]How to plot the first day start of rainfall season with specific conditions with netcdf data on certain area?

我有 NetCDF 每日降水量数据,尺寸为:时间:153(我裁剪了 NC 文件,所以它的第一个日期是 8 月 1 日),经度:401,纬度:121。

我想计算 plot 在某些地区雨季的第一天,条件如下:雨季的开始日期定义为前 5 个连续的雨天至少接收 40 毫米,随后没有连续 10 个干燥天,在发病日期后的 30 天内至少接受 5 毫米。 8月1日后开始计算。

我已经尝试在空间上对它进行 plot,但我想它会花费这么多时间来处理一年的数据,因为我必须对 plot 10 年的数据进行处理。 所以,我正在寻找一种更方便的方法来做到这一点,而我目前正在为一个点做一些代码(我希望日期在某个区域的空间上绘制)如下所示:

import pandas as pd
import xarray as xr
import numpy as np
file='CMA.nc'

data = xr.open_dataset(file)
precip = data['tp']

#Single point 
point = precip.sel(lon=106.11, lat=-6.11, method='nearest')
point.plot()

def wet_onset_date(data):
array = data.values

count1 = 0 
count2 = 5 
wet_onset = []
onset_date = []

while count2 <= array.size:
    wet_onset.append(array[count1:count2].sum())
    tonset_date.append(count1)
    count1 += 1
    count2 += 1
    
'''dry spell'''
count3 = 5
count4 = 5+30
thirty = []
dry_spell = []

while count4 <= array.size:
    thirty.append(array[count3:count4])
    
    for each_30 in thirty:
        count5 = 0
        count6 = 11
        weekly_sum = []
        while count6 <= thirty[0].size:
            weekly_sum.append(each_30[count5:count6].sum())
            count5 += 1
            count6 += 1
    if np.min(weekly_sum) <= 5:
        dry_spell.append(True)
    else:
        dry_spell.append(False)
        
    count3 += 1
    count4 += 1 
    
wet_onset_final = wet_onset[:len(dryspell)]
onset_final_date = onset_date[:len(dry_spell)]

for rain, not_dry, date in zip(wet_onset_final, dry_spell, onset_final_date):
    if (rain >= 40) and (not_dry == false):
        target_date = data.isel(time=date).time.values
        return target_date
        break
on = wet_onset_date(point)
print(on)

>> 2017-11-27T00:00:00.000000000

让我们从这个问题的最小可重现示例 (MRE)开始。 您需要一个包含降水量数组的数据集,其中至少包含一整年的每日时间序列数据,以及其他几个维度:

import xarray as xr, pandas as pd, numpy as np

x = np.arange(-110.5, 100)
y = np.arange(30.5, 40)
time = pd.date_range('2020-01-01', '2022-12-31', freq='D')

# generate random precip-ish data
random_lognorm = np.exp(np.random.random(size=(len(time), len(y), len(x)))) * 200

# random seasonal-ish mask
raining = (
    (time.dayofyear.values.reshape(-1, 1, 1)
    * np.random.random(size=random_lognorm.shape)) > 40
)

# finally, precip is the rain array * the "is raining" array
pr = random_lognorm * raining

# now we can construct an xarray Dataset with this data to form our MRE
ds = xr.Dataset(
    {'pr': (('time', 'lat', 'lon'), pr)},
    coords={'lat': y, 'lon': x, 'time': time},
)

这是它的样子:

In [7]: ds
Out[7]:
<xarray.Dataset>
Dimensions:  (time: 1096, lat: 10, lon: 211)
Coordinates:
  * lat      (lat) float64 30.5 31.5 32.5 33.5 34.5 35.5 36.5 37.5 38.5 39.5
  * lon      (lon) float64 -110.5 -109.5 -108.5 -107.5 ... 96.5 97.5 98.5 99.5
  * time     (time) datetime64[ns] 2020-01-01 2020-01-02 ... 2022-12-31
Data variables:
    pr       (time, lat, lon) float64 0.0 0.0 0.0 0.0 ... 413.6 308.0 386.9

与 numpy 和 pandas 中的性能类似,要有效地处理 xarray 对象中的大型 arrays,最好弄清楚如何使用数组操作而不是遍历元素。 这对于窗口/滚动操作来说绝对是正确的。 查看 xarray 用户指南中的滚动窗口操作指南 - 这是对该主题的有用介绍。

我不完全理解您要在此处应用的所有条件,但我可以将一些内容放入快速演示中,希望对您有所帮助。

xarray 中一个真正有用的功能是滚动模块的construct方法。 DataArrayRollingDatasetRolling对象的这种方法返回一个重组后的 DataArray/Dataset(分别),并将 window 滚动到原始数组中。 所以在下面,我指定滚动 window time=30 construct 方法为数组提供了一个重塑的“视图”,这是一种重塑数据的内存高效方式,它提供了一个新维度(我在下面将其命名为“窗口”),您可以沿着该维度处理滚动数据。

In [8]: rolled = ds.pr.rolling(time=30, min_periods=30).construct('window')

In [9]: rolled
Out[9]:
<xarray.DataArray 'pr' (time: 1096, lat: 10, lon: 211, window: 30)>
array([[[[         nan,          nan,          nan, ...,          nan,
                   nan,   0.        ],
         [         nan,          nan,          nan, ...,          nan,
                   nan,   0.        ],
         [         nan,          nan,          nan, ...,          nan,
                   nan,   0.        ],
...
         ...,
         [443.96641513, 524.82969347, 419.95639311, ...,   0.        ,
          500.87393858, 413.55965161],
         [352.36603332, 427.1653476 , 236.46898157, ..., 469.71452213,
          235.31558598, 308.02273055],
         [396.360887  , 520.49089188, 242.73958665, ..., 234.32972887,
          252.48534392, 386.93237596]]]])
Coordinates:
  * lat      (lat) float64 30.5 31.5 32.5 33.5 34.5 35.5 36.5 37.5 38.5 39.5
  * lon      (lon) float64 -110.5 -109.5 -108.5 -107.5 ... 96.5 97.5 98.5 99.5
  * time     (time) datetime64[ns] 2020-01-01 2020-01-02 ... 2022-12-31
Dimensions without coordinates: window

我们可以使用这个 window 维度,就好像它是我们数据集中每组 30 天一样。 所以现在我们可以定义一个任意复杂的 function 来减少我们的window维度:

def complex_condition(rolled):
    # first 5 days are > 40mm
    first_5d_over_40mm = (rolled.isel(window=slice(None, 5)) > 40).all(dim='window')
    # first 30 days are > 5 mm
    all_30d_over_5mm = (rolled > 5).all(dim='window')
    # result is True when both conditions are met
    return first_5d_over_40mm & all_30d_over_5mm

这可以简单地应用于滚动数据集:

In [11]: meets_criteria = complex_condition(rolled)

In [12]: meets_criteria
Out[12]:
<xarray.DataArray 'pr' (time: 1096, lat: 10, lon: 211)>
array([[[False, False, False, ..., False, False, False],
        [False, False, False, ..., False, False, False],
        [False, False, False, ..., False, False, False],
...
        [False, False, False, ..., False, False, False],
        [False, False, False, ..., False, False, False],
        [False, False, False, ..., False, False, False]]])
Coordinates:
  * lat      (lat) float64 30.5 31.5 32.5 33.5 34.5 35.5 36.5 37.5 38.5 39.5
  * lon      (lon) float64 -110.5 -109.5 -108.5 -107.5 ... 96.5 97.5 98.5 99.5
  * time     (time) datetime64[ns] 2020-01-01 2020-01-02 ... 2022-12-31

现在,我们可以使用idxmax找到满足这些条件的第一个索引(确保屏蔽掉任何不满足条件的单元格):

In [13]: meets_criteria.idxmax(dim='time').where(meets_criteria.any(dim='time'))
Out[13]:
<xarray.DataArray 'time' (lat: 10, lon: 211)>
array([[                          'NaT',                           'NaT',
                                  'NaT', ...,
                                  'NaT',                           'NaT',
        '2022-12-02T00:00:00.000000000'],
       ['2020-12-14T00:00:00.000000000',                           'NaT',
        '2020-12-20T00:00:00.000000000', ...,
                                  'NaT', '2021-09-22T00:00:00.000000000',
        '2021-10-20T00:00:00.000000000'],
       ['2021-12-24T00:00:00.000000000',                           'NaT',
        '2021-12-26T00:00:00.000000000', ...,
                                  'NaT', '2022-12-18T00:00:00.000000000',
                                  'NaT'],
       ...,
       ['2021-08-21T00:00:00.000000000',                           'NaT',
                                  'NaT', ...,
        '2021-08-06T00:00:00.000000000', '2020-11-07T00:00:00.000000000',
        '2022-10-04T00:00:00.000000000'],
       [                          'NaT', '2020-12-11T00:00:00.000000000',
                                  'NaT', ...,
        '2020-12-18T00:00:00.000000000', '2022-10-31T00:00:00.000000000',
                                  'NaT'],
       ['2021-09-28T00:00:00.000000000', '2020-11-18T00:00:00.000000000',
                                  'NaT', ...,
        '2021-10-14T00:00:00.000000000',                           'NaT',
                                  'NaT']], dtype='datetime64[ns]')
Coordinates:
  * lat      (lat) float64 30.5 31.5 32.5 33.5 34.5 35.5 36.5 37.5 38.5 39.5
  * lon      (lon) float64 -110.5 -109.5 -108.5 -107.5 ... 96.5 97.5 98.5 99.5

需要注意的一件事是,默认情况下滚动 window 将返回 window 末尾的索引。如果您想要 window 的开始,您可以使用da.shift重新索引meets_criteria结果。

您在问题中提到了许多其他内容,但对于单个问题来说,这是很多 scope。 希望这能为您指明正确的方向!

另外,请注意 - 当您 plot 和 map 次时,您将获得每个日期时间 object 的数字表示, nanoseconds since 1970为单位,因此结果将是一个大得离谱的数字。 如果愿意,您可以使用每个 datetime 对象的dayofyear属性获取一年中的第几天,例如:

In [14]: (
    ...:     meets_criteria
    ...:     .groupby('time.year')
    ...:     .apply(lambda x: x.idxmax(dim='time').dt.dayofyear.where(x.any(dim='time')))
    ...: )
Out[14]:
<xarray.DataArray 'dayofyear' (year: 3, lat: 10, lon: 211)>
array([[[ nan,  nan,  nan, ...,  nan,  nan,  nan],
        [349.,  nan, 355., ...,  nan,  nan,  nan],
        [ nan,  nan,  nan, ...,  nan,  nan,  nan],
        ...,
        [ nan,  nan,  nan, ...,  nan, 312.,  nan],
        [ nan, 346.,  nan, ..., 353.,  nan,  nan],
        [ nan, 323.,  nan, ...,  nan,  nan,  nan]],

       [[ nan,  nan,  nan, ...,  nan,  nan,  nan],
        [ nan,  nan,  nan, ...,  nan, 265., 293.],
        [358.,  nan, 360., ...,  nan,  nan,  nan],
        ...,
        [233.,  nan,  nan, ..., 218., 278.,  nan],
        [ nan,  nan,  nan, ...,  nan,  nan,  nan],
        [271.,  nan,  nan, ..., 287.,  nan,  nan]],

       [[ nan,  nan,  nan, ...,  nan,  nan, 336.],
        [ nan,  nan,  nan, ...,  nan,  nan,  nan],
        [ nan,  nan, 305., ...,  nan, 352.,  nan],
        ...,
        [217.,  nan,  nan, ...,  nan,  nan, 277.],
        [ nan, 357.,  nan, ...,  nan, 304.,  nan],
        [267., 314.,  nan, ...,  nan,  nan,  nan]]])
Coordinates:
  * lat      (lat) float64 30.5 31.5 32.5 33.5 34.5 35.5 36.5 37.5 38.5 39.5
  * lon      (lon) float64 -110.5 -109.5 -108.5 -107.5 ... 96.5 97.5 98.5 99.5
  * year     (year) int64 2020 2021 2022

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM