簡體   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