読者です 読者をやめる 読者になる 読者になる

Met Post

Python、プログラミングのメモ、気象、海洋のこととか

雨量予想をプロットしてみた

xraycartopyで雨量予想をプロットする。ピークの値を表示してそれっぽくプロットする方法を調べてみた。

ピークの検出

以下のFAQが参考になった。

stackoverflow.com

隣接する格子でのピークを参照するためにScipyのndimage.filters.maximum_filterを使った。

maximum_filterで隣接格子の最大値でフィルターしたデータを用意して、元データと比較すればピークの格子を特定できる。

import numpy as np
import numpy.random as random
from scipy.ndimage.filters import maximum_filter

# ランダムデータ
data = random.rand(25,25)
# 各格子を隣接5格子のうち最大の値でフィルターして置き換える
local_max = maximum_filter(data, footprint=np.ones((5,5)), mode='constant')
# 元のデータとフィルターしたデータで値が同じ格子(ピーク格子)以外をマスクする
peak = np.ma.array(data, mask=~(data==local_max))

import matplotlib.pyplot as plt
plt.subplot(2,2,1)
plt.pcolormesh(data, vmin=0, vmax=1)
plt.title('Original')
plt.colorbar()

plt.subplot(2,2,2)
plt.pcolormesh(local_max, vmin=0, vmax=1)
plt.title('Filtered')
plt.colorbar()

plt.subplot(2,2,3)
plt.pcolormesh(peak, vmin=0, vmax=1)
plt.title('Peak')
plt.colorbar()

plt.show()

f:id:ttmych:20160117212342p:plain

プロットしてみる

メソモデルの1時間雨量の予想をプロットしてみた。

import cartopy.crs as ccrs
import matplotlib.pyplot as plt
import matplotlib.patheffects as PathEffects

import xray
import numpy as np

## select data
# 1時間雨量から東日本の範囲をxray.dataArrayで取得
ncfile = 'http://opendap.rish.kyoto-u.ac.jp/opendap/hyrax/jmadata/gpv/latest/MSM-S.nc'
ds = xray.open_dataset(ncfile)
darray = ds['r1h'].sel(lat=slice(38,32),lon=slice(133,143))[18,:,:]

## for annotation
# 数値プロットのために座標を2dのnumpy.ndarrayにしておく
ylab, xlab = darray.dims
xval = darray[xlab].values
yval = darray[ylab].values
xval, yval = np.meshgrid(xval, yval)

## detect peak
# 隣接15格子のピークかつR1=1mm以上の座標を算出
from scipy.ndimage.filters import maximum_filter

zval = darray.to_masked_array(copy=False)
local_max = maximum_filter(zval, footprint=np.ones((15,15)), mode='constant')
local_max[0,:]  = np.ma.masked
local_max[-1,:] = np.ma.masked
local_max[:,0]  = np.ma.masked
local_max[:,-1] = np.ma.masked
mask = (zval == local_max) & (zval >=1)

## for colormap
colors = ['#FFFFFF', '#00FFFF', '#00B0FF', '#0070FF', '#228B22', '#00FF00', '#FFFF00', '#FF8000', '#FF0000', '#FF00FF']
levels = [1,3,5,10,20,30,40,50,80]

## plot
plt.figure(figsize=(8,5))
ax = plt.axes(projection=ccrs.Mercator())
transform = ccrs.PlateCarree()._as_mpl_transform(ax)
darray.plot(ax=ax, levels=levels, colors=colors, extend='both', transform=transform)
for x, y, val in zip(xval[mask].flat, yval[mask].flat, zval[mask].flat):
    val = '{}'.format(int(val))
    ax.plot(x, y, '+', color='k', mew=1, ms=6, transform=transform)
    ax.annotate(val, xy=(x,y), xytext=(1, -1), xycoords=transform,
                textcoords='offset points',  ha='left', va='top', fontsize=10,
                path_effects=[PathEffects.withStroke(linewidth=2, foreground='w')])
ax.coastlines('10m')
plt.show()

f:id:ttmych:20160117212345p:plain

メモ

地図座標への変換はCartopyを使っている。matplotlibのannotateを使って変換する場合は次のようにすればいいらしい。

ax = plt.axes(projection=ccrs.Mercator())
transform = ccrs.PlateCarree()._as_mpl_transform(ax)
ax.annotate(val, xy=(x,y), xycoords=transform)

こちらのFAQを参考にした。 stackoverflow.com