当前位置:首页>python>Python | 降水概率密度分布图

Python | 降水概率密度分布图

  • 2026-09-07 00:20:31
Python | 降水概率密度分布图

写在前面

最近终于把之前的工作收尾了,就等老外再看一遍了。开始一个新的项目,从复现老外的文章开始。

主要包括:

  • 1、降水概率密度分布
  • 2、根据个别日降水率计算年平均降水量和热带平均降水量
  • 3、从2的结果中计算累计降水
这里使用的降水为GPM-daily观测资料,2020.02.01-2021.01.31,分辨率为1度

降水概率密度分分布

第一个较为简单,通过设置不同的bins,统计每个bins中降水的分布即可。

BIN_EDGES_MM_DAY = (
0.0, 0.1, 1, 2, 3, 4, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50,
60, 70, 80, 90, 100, 125, 150, 175, 200, 225, 250, 275, 300,

)
pdf_density, bin_edges = np.histogram(ds, bins=BIN_EDGES_MM_DAY, density=True)
plt.plot(BIN_EDGES_MM_DAY[:-1], pdf_density, drawstyle='steps-post')
plt.xscale('log')
plt.yscale('log')
plt.xlabel('Precipitation (mm/day)')
plt.ylabel('Probability Density')
plt.title('Precipitation Probability Density Function')
plt.grid(True, which='both', linestyle='--', linewidth=0.5)
plt.show()

每个降水区间对总降水的贡献占比 = 每个区间的总降水 / 总降水

本质上是为了,基于之前分的不同降水区间,去计算每个降水区间贡献了多少总降水:降水率落在 τ 到 τ+δτ 这一区间内时,对全年热带平均降水的贡献,这可以回答以下问题:

  • 总降水主要来自哪个强度区间?
  • 小雨、中雨、暴雨,谁对总降水贡献最大?

上述公式的分子A(lon,lat,time)类似一个掩膜的作用,如果某个格点在某一天的降水数值满足τ 到 τ+δτ,例如[0,1],那么将这个格点mask为1,否则为0,目的就是为了只保留该降水区间内降水格点,其他都置为0.这是为了方便统计这一降水区间[0,1]对热带平均降水的贡献。

在此基础上,需要进一步计算每个降水区间实际占据了多少面积,所以这里需要计算实际的经纬度网格的格点之间的球面积,考虑到lat不同范围进行cos加权。


defcal_area(dset, x_step=None, y_step=None):
"""Calculate the horizontal area of each lat-lon grid box.
    dx=RcosϕΔλ
    dy=RΔϕ
    area=dx*dy=R^2cosϕΔλΔϕ
    delta x = x_step (degree) x pi/180 x Earth radius
    delta y = y_step (degree) x pi/180 x Earth radius
    """

if x_step isNone:
        x_step = float(np.abs(np.diff(dset.lon.values)).mean())
if y_step isNone:
        y_step = float(np.abs(np.diff(dset.lat.values)).mean())

    earthr = 6.371e6
    lon2d, lat2d = np.meshgrid(dset.lon.values, dset.lat.values)
    area = xr.DataArray(
        data=(x_step / 180 * np.pi) * earthr * np.cos(np.deg2rad(lat2d)) * (y_step / 180 * np.pi) * earthr,
        dims=["lat", "lon"],
        coords={"lat": dset.lat.values, "lon": dset.lon.values},
    )
return area

area = cal_area(ds)
precip_values = ds.values.reshape(-1) # flattern to 1D array
area_values = np.broadcast_to(area.values, ds.shape).reshape(-1) # flattern
area_total, _ = np.histogram(precip_values, bins=BIN_EDGES_MM_DAY, weights=area_values) 

再次调用histogram函数,将面积权重加进去,得到每个降水区间占了多少面积,预期统计结果大概就是:

  • 0–1 mm/day 的降水,对应总面积是多少
  • 1–5 mm/day 的降水,对应总面积是多少
  • 5–10 mm/day 的降水,对应总面积是多少 以下结果很显而易见,小雨部分占据了最多的面积

进一步的,但是我们需要思考的是,小雨占据了最大的空间面积,他对于总降水的贡献就是最重要的吗?

  • 计算每个降水区间对应的总降水量贡献,计算落进不同降水区间以后加多少权重,比如得到:
  • 20–30 mm/day 的区域一共下了多少雨?
precip_total, _ = np.histogram(
        precip_values,
        bins=   BIN_EDGES_MM_DAY,
        weights=precip_values * area_values,
    )     
plt.plot(BIN_EDGES_MM_DAY[:-1], precip_total, drawstyle='steps-post')
plt.xscale('log')
plt.xlabel('Precipitation (mm/day)')
plt.ylabel('Probability Density')
plt.title('Precipitation Probability Density Function')
plt.grid(True, which='both', linestyle='--', linewidth=0.5)
plt.show()
  • 贡献更大的反而是5-10mm/day左右的降水,对于总降水贡献最大。

进一步计算,第 i 个降水区间对区域平均降水的贡献。

total_area = area_values.sum() # 计算总面积
bin_mean_contribution = precip_total / total_area 
plt.plot(BIN_EDGES_MM_DAY[:-1], bin_mean_contribution, drawstyle='steps-post')
plt.xscale('log')
plt.xlabel('Precipitation (mm/day)')
plt.ylabel('Contribution to Total Precipitation')
plt.title('Contribution of Each Precipitation Bin to Total Precipitation')
plt.grid(True, which='both', linestyle='--', linewidth=0.5)
plt.show()

进一步计算:从小雨到大雨逐步累加时,各降水强度对总降水的累计贡献。cumulative_precip = np.cumsum(bin_mean_contribution)

绘图比较:

plot_df = distribution_df.loc[distribution_df['bin_center_mm_day'] > 0].copy()
pdf_df = plot_df.loc[plot_df['pdf_density'] > 0].copy()

fig = plt.figure(figsize=(12, 6))
gs = fig.add_gridspec(
    nrows=2,
    ncols=2,
    width_ratios=(1.45, 1.0),
    height_ratios=(1.0, 1.0),
    wspace=0.28,
    hspace=0.32,
)

ax_pdf = fig.add_subplot(gs[:, 0])
ax_bin = fig.add_subplot(gs[0, 1])
ax_cum = fig.add_subplot(gs[1, 1])

line_kwargs = dict(
    color='
#1f4e79',
    lw=2.2,
    marker='o',
    ms=3.8,
    markerfacecolor='white',
    markeredgewidth=0.9,
    solid_capstyle='round',
)

ax_pdf.plot(pdf_df['bin_center_mm_day'], pdf_df['pdf_density'], **line_kwargs)
ax_bin.plot(plot_df['bin_center_mm_day'], plot_df['bin_mean_contribution_mm_day'], **line_kwargs)

bar_left = plot_df['bin_left_mm_day'].to_numpy(copy=True)
bar_width = (plot_df['bin_right_mm_day'] - plot_df['bin_left_mm_day']).to_numpy()

# The first bin starts at 0 mm/day, which cannot be shown directly on a log x-axis.
if bar_left[0] <= 0:
    bar_left[0] = plot_df['bin_center_mm_day'].iloc[0] * 0.5
    bar_width[0] = plot_df['bin_right_mm_day'].iloc[0] - bar_left[0]

ax_bin.bar(
    bar_left,
    plot_df['bin_mean_contribution_mm_day'],
    width=bar_width,
    align='edge',
    facecolor='none',
    edgecolor='#1f4e79',
    linewidth=0.8,
    alpha=0.9,
    zorder=1,
)
ax_cum.plot(plot_df['bin_center_mm_day'], plot_df['cumulative_fraction'], **line_kwargs)

x_min = float(plot_df['bin_center_mm_day'].iloc[0])
x_max = float(plot_df['bin_center_mm_day'].iloc[-1])

for ax in (ax_pdf, ax_bin, ax_cum):
    ax.set_xscale('log')
    ax.set_xlim(x_min * 0.9, x_max * 1.05)
    ax.grid(True, which='major', color='#d0d0d0', lw=0.6, alpha=0.8)
    ax.grid(True, which='minor', color='#ececec', lw=0.4, alpha=0.9)
    ax.tick_params(which='both', direction='in', top=False, right=False)
    ax.spines['top'].set_visible(False)
    ax.spines['right'].set_visible(False)
    ax.xaxis.set_major_locator(LogLocator(base=10.0))
    ax.xaxis.set_minor_locator(LogLocator(base=10.0, subs=np.arange(2, 10) * 0.1))
    ax.xaxis.set_minor_formatter(NullFormatter())

ax_pdf.set_yscale('log')
ax_pdf.set_xlabel('Precipitation rate (mm day$^{-1}$)')
ax_pdf.set_ylabel('PDF density')
ax_pdf.text(0.02, 0.98, '(a)', transform=ax_pdf.transAxes, ha='left', va='top', fontweight='bold')
ax_pdf.set_title('PDF of precipitation rates', loc='left', pad=10)

# This is the mean precipitation contributed by each bin to the whole sample.
ax_bin.set_ylabel(r'$\overline{[P]}_{\tau}^{\tau + \delta\tau}$ (mm day$^{-1}$)')
ax_bin.text(0.02, 0.98, '(b)', transform=ax_bin.transAxes, ha='left', va='top', fontweight='bold')
ax_bin.set_title('Mean precipitation contributed by each bin', loc='left', pad=10)

ax_cum.set_xlabel('Precipitation rate (mm day$^{-1}$)')
ax_cum.set_ylabel(r'$\frac{\overline{[P]}_{0}^{\tau}}{\overline{[P]}_{0}^{\infty}}$')
ax_cum.text(0.02, 0.98, '(c)', transform=ax_cum.transAxes, ha='left', va='top', fontweight='bold')
ax_cum.set_title('Cumulative contribution', loc='left', pad=10)
ax_cum.set_ylim(0.0, 1.02)
ax_cum.axhline(0.5, color='#b7b7b7', lw=0.8, ls='--', zorder=0)
ax_cum.axhline(0.9, color='#d0d0d0', lw=0.8, ls=':', zorder=0)

plt.show()

下面是原文的结果:

原文描述细节

为了分析热带降水的日常变化(以下也称为热带降水变化),我们遵循 Atlas 等人(1990)引入的框架。 我们首先根据**个别日降水率计算年平均降水量和热带平均降水量**:

左侧的术语表示从到的年平均热带降水量的降水率,例如从(0.1 mm/day 到1 mm/day)

使用所有降水率得出年热带平均降水量。

  • 其中, 和 分别表示对于空间和时间到平均。

表示热带求和,分别沿着经度和纬度

这里定义热带纬度范围是30S-30N,P 为格点降水率, 是一个掩膜,对于任何一个时刻某一个空间的网格点降水,进行判断,

如果满足,

那么取1,否则取0

举个例子,如果一个时刻上某一个空间网格点到降水大于0.1mm/day,小于1mm/day,就把这个格点取为1,否则为0.

★

Segura, H., and C. Hohenegger, 2024: How Do the Tropics Precipitate? Daily Variations in Precipitation and Cloud Distribution. Journal of the Meteorological Society of Japan, 102, 525–537, https://doi.org/10.2151/jmsj.2024-028.

最新文章

随机文章