2014年11月11日火曜日
Surface velocity data of MOVE/MRI.com at NEAR-GOOS RRTDB
NEAR-GOOSのRegional Real Time Databaseのサイトは、最近更新されて、データのダウンロードがregistration無しでダウンロードできるようになった(自動ダウンロードを行うにはregistrationが必要)。
ここでは、その中から、気象庁(JMA)のDaily Surface Currents in the seas adjacent to Japanをプロットして見る。
2014年11月6日のデータ "move_subc_jpn_D20141106.txt"をダウンロードして置き、CartopyでプロットするIPython Notebookはこちら。
https://www.dropbox.com/s/bpow09n6x4rm9sy/MOVE_velocity.ipynb?dl=0
2014年10月30日木曜日
Colors (diverging data)
前回はsequential data用のカラーマップについてテストしたが、今回は正負のアノマリなどをプロットする diverging カラーマップについてテストした。
ipython notebookはこちら
http://nbviewer.ipython.org/urls/dl.dropbox.com/s/t8um9tdmauu8qpv/divergent_color.ipynb?dl=0
テストデータのしてはNOAA OISST version 2の海面温度アノマリを使った。データ読み込みとプロットにはIrisを使った。
Irisはイギリスのソフトのためか、日付変更線をまたぐ場合には少し癖があり、そのデモでもある。
2014年10月28日火曜日
Colors (sequential data)
最近、カラーマップに関する考察をいくつか読んだ。
- THE RAINBOW IS DEAD…LONG LIVE THE RAINBOW!
http://mycarta.wordpress.com/2012/05/29/the-rainbow-is-dead-long-live-the-rainbow-series-outline/ - Subtleties of Color
http://earthobservatory.nasa.gov/blogs/elegantfigures/2013/08/05/subtleties-of-color-part-1-of-6/ - Stauffer, R., G. J. Mayr, M. Dabernig, and A. Zeileis, 2014: Somewhere over the rainbow: How to make effective use of colors in meteorological visualizations. Bulletin of the American Meteorological Society, 140710055335002. doi:10.1175/bams-d-13-00155.1
それに対する代替はいくつか提案されている。
以下のipython notebookでは、それらを試してみた。
http://nbviewer.ipython.org/urls/dl.dropbox.com/s/5t9jrhr7va3wscj/colors.ipynb?dl=0
http://nbviewer.ipython.org/urls/dl.dropbox.com/s/5t9jrhr7va3wscj/colors.ipynb?dl=0
下は"cube1"と呼ばれるカラーマップでプロットした例。
ちなみに、この日の海面温度には台風19号と台風20号の通過に伴い、海水の低下した場所が見られる。
Reference
Kuroshio Oyashio Watch 2014/10/20
2014年10月26日日曜日
等値線の位置を求める
Qiu and Chen (2005)などでは、海面高度データのある等値線の位置を黒潮続流の位置とし、Decadal Variationの議論している。
等値線の位置を決めるのは、渦などの紛らわしい等値線があり、目でみていちいち確認しないで自動的に欲しい等値線の位置を決めるのは難しい。
ここでは、図作成ソフトmatplotlibのcontourルチーンから情報を取り出して、等値線の位置を決める工夫をする。
参考にしたのはstackoverflowの
- How can I get the (x,y) values of the line that is ploted by a contour plot (matplotlib)? http://stackoverflow.com/questions/1560424/how-can-i-get-the-x-y-values-of-the-line-that-is-ploted-by-a-contour-plot-mat
- matplotlib - extracting data from contour lines http://stackoverflow.com/questions/5666056/matplotlib-extracting-data-from-contour-lines
- Python: find contour lines from matplotlib.pyplot.contour() http://stackoverflow.com/questions/18304722/python-find-contour-lines-from-matplotlib-pyplot-contour/18309914#18309914
ipythonノートブックは
http://nbviewer.ipython.org/urls/dl.dropbox.com/s/qt804lsufj4whyx/Kuroshio_extension_path.ipynb?dl=0
Step1 力学高度のデータをferretを使い、読み込み、図示する
データはAVISOの絶対力学高度の2009年1月21日のデータを用いる。データはAVISOからダウンロードしておく。
データの読み込みと図示には、前回紹介したferret magicを使う。
Qiu and Chen (2005)では東経141から153度のデータで議論しているので、その範囲だけ抜き出しておく。
等値線は、渦や蛇行のなどのため等値線が4つあるが、黒潮続流にあたる本来欲しい線(東西にのびる線)だけを取り出すのが課題である。
Step 2 Ferretからpythonにデータを読み込む
matlabの機能を使うために、ferretからpythonへとデータを読み込む。これもferret magicを用いる。データがちゃんと読めているかを確認もしておく。
Step 3 等値線の位置を求める
matlabのcontour routineの機能を使って、等値線の位置を求める。等値線の位置は4つ求まっている。
Step 4 等値線の位置情報から、もっとも長い等値線を選ぶ。
等値線の位置が数値的に求まったので、この中から、欲しいpathだけを選ぶ。最も長いpathが黒潮続流にあたる欲しいpathだと考えられる(渦などを避けるために、始点と終点がもっとも離れているpathという条件でも良いかもしれない。)。
まず、pathの長さを求める関数を作成する。
get_distance は2点間の距離を km で求める関数。
get_pathlength はget_distanceを用いてpath位置の情報の配列からpathの長さを求める関数。
上の4つのpathの長さを求め、path #2が最も長いことがわかる(約1432km)。
path #= 0 length= 415.785621835 km
path #= 1 length= 527.959783762 km
path #= 2 length= 1432.08536051 km
path #= 3 length= 563.215908518 km
これが、求めるpathである。
Reference:
Qiu, B., and S. Chen, 2005: Variability of the Kuroshio Extension Jet, Recirculation Gyre, and Mesoscale Eddies on Decadal Time Scales. Journal of Physical Oceanography, 35, 2090-2103. doi:10.1175/JPO2807.1
2014年9月6日土曜日
surface drifter
NOAA, Atlantic Oceanographic and Meteorological Laboratory (AOML)のGlobal Drifter Program (GDP), Drifter Data Assembly Center (DAC)には表層漂流ブイのアーカイブがある。このデータを読み込んで図示してみる。
サイトからftpでデータをあらかじめダウンロードしておく。このうち、buoydata_10001_mar14.dat (ブイ1万個目以降から2014年3月までのデータ)を例として扱う。
IPython Notebookはこちら。
http://nbviewer.ipython.org/urls/dl.dropbox.com/s/uzv1bktgazcf821/Test_buoys.ipynb?dl=0
まず、pandasでデータを読み込む。データが多量なので、読み込むまで時間がかかるかもしれない。
データ(data)の内で、一部に緯度が北緯25から45度、東経120から160度が含まれるデータを選びだす(selecteddata)。そのうちで、ユニークなid番号を持つもののは851個ある。
あらためて、もとのデータ(data)から、そのid番号を持つデータを抜き出し(wanteddata)、pickle形式で保存する。
次に、そのデータの中から、例として最初の10個だけcartopyを用いてプロットした。
参考文献
2014年8月7日木曜日
IrisとETOPO1
Irisはイギリスで開発されているpythonベースの気象・海洋データ解析パッケージである。
Irisを使って地形データETOPO1を読み込んで、プロットしたり、補間してみた。
ETOPO1は1/60°の海底地形で、NOAA NGDCのサイトからETOPO1 Bedrock(氷無しの地形)、cell-registered(グリッドセルの位置で定義される)の中から、netcdfファイル ETOPO1_Bed_c_gmt4.grdをダウンロードした。
IPython Notebookはこちらである。
http://nbviewer.ipython.org/urls/dl.dropbox.com/s/67khdbgzc2bf0sp/Read_ETOPO1.ipynb
下の図はプロットの一例。
2014年2月11日火曜日
bokehを使って、串本浦神の潮位差をプロット
串本と浦神の潮位差のデータをbokehを使ってプロットしてみる。bokehはpythonのプロットライブラリの一つで、ズームなどが可能なインタラクティブなプロットをweb上につくることができる。(bokehは日本語のボケから来てるらしい。何故そんな名前にしたんだか。)
ipython notebookはこちら。
http://nbviewer.ipython.org/urls/dl.dropbox.com/s/rry6nt3xs49o6s6/KushimotoUragami.ipynb
ズームなどができるのを確認してみてください。
データは以前のようにpandasで読み込んでいる。
daily dataの黒線で、30日の移動平均を赤線でプロットしている。ここでの30日平均は基準日を中心とした30日平均ではなく、基準日をさかのぼっての30日平均であることに注意。
2013年4月17日水曜日
Numba
Pythonでforをまわすような数値計算を行うとmatlabなどと同じで非常に遅い。
それを克服するためにpypyやcythonなどがある。しかし基本的にコードを書き換える必要があるので、もっと楽をしたい。
最近numbaというものを知った。ここのサンプルにある例だと、
from numba import autojit
@autojit
のおまじないだけで関数が劇的に早くなる。
少し、自分で例で実験してみた。
全球のSSTに対して、NINO3の相関をとるということをやってみる(これはnumbaの実験のために作った例であり、相関をとるだけならもっとエレガントな方法があるだろう)。
そのノートブックが
http://nbviewer.ipython.org/5396344
説明
(1) 図をプロットするためのおまじない。
(2) SSTアノマリとNINO3を読む関数を定義。
元データは NOAA OISST v2でmonthly dataのsst.mnmean.ncを使う。
データはPython Interface to GrADSを使って読む。
1982から2010年のデータから気候値からのanomaly(Bin Guan's GrADS Script Libraryのdeseasonを使った。古いバージョンを使ったので、今は使い方が違うかも知れない)とNINO3 SSTアノマリを定義し、返す。
ここらへんは以前の記事も参照。
/usr/local/lib/python2.7 なんちゃらというメッセージは私の環境でインストール上のゴミなので気にしないで。
(3) 上で定義した関数を呼んでいる。
(4) 時系列xと二次元時系列(水平2次元と時間の3次元)から2次元の相関係数を返す関数。
from numba import autojit
@autojit
の部分がnumba.
(5) ベンチマーク
この場合、5.7秒かかっている。
もし上で@autojitを付けない場合、7.34秒だった。
つまりnumbaを使っていることで、確かに速くなっているが、劇的にではなかった。
これは、forでまわしている中身がプリミティブな式ではなくて、numpyの関数corrcoefであるからだろうか。
ちなみに、欠損値処理は何もやっていないので、warningが出ている。この場合はプロットするときに陸地のデータはマスクするので、これで構わない。
欠損値処理もできるma.corrcoefを使うとかなり遅くなる。
numbaを使わない場合で50.2秒、numbaを47.5秒だった。
(6) 実際に相関係数を求める。
(7) land sea maskを読む関数
(8) land sea maskを読む
(9) プロット
エルニーニョに典型的な馬蹄形が見られる。インド洋ダイポールへの相関も見られる。
結論
今回試したケースでは、劇的というほどではないが、ちょっとした追加で、確かに速くはなった。場合によっては劇的に速くなる場合もあるだろう。。今後の進展に期待したい技術である。
2013年4月2日火曜日
IPython Notebook
IPython Notebookで解析して、それをパブリックに表示するデモンストレーション。
作ったnotebookはIPytnon Notebook viewerを使って、ここで見られる。
http://nbviewer.ipython.org/urls/dl.dropbox.com/u/439394/ipyhon/seaice.ipynb
- データとしては、北極海海氷面積データのcsvでダウンロード
- pandasでデータを読み、9月の平均データを作る。
- IPythonのRmagicを使い、線形回帰を行いトレンドラインを引く
参考文献
2012年7月26日木曜日
NCEP Climate Forecast System Reanalysis
NCEP Climate Forecast System Reanalysisというデータがある。
http://cfs.ncep.noaa.gov/cfsr/
大気海洋モデル結合モデルに対してデータ同化が行われているのが特色だ。
分解能は従来のNCEPの再解析よりも高い。
大気: 水平分解能~38 km (T382)、 鉛直64 levels
海洋: 熱帯で0.25度、それ以外で0.5度の水平分解能、鉛直40 levels
また変数によっては1時間間隔のデータがある。
もっとも、データ同化が行われるのは6時間間隔だから、その間は予報データでうめてある。
このデータを見てみた。
UCARのサイトの
http://rda.ucar.edu/pub/cfsr.html
NCEP Climate Forecast System Reanalysis (CFSR) Selected Hourly Time-Series Products, January 1979 to December 2010http://rda.ucar.edu/datasets/ds093.1/
から、2001年の12月のSSTデータ(中身は海面下5mの温度)
ocnsst.gdas.200112.grb2
をダウンロードした。
これはgrib2形式なので、これをwgrib2でgrads形式に変換する。
g2ctl ocnsst.gdas.200112.grb2 > sst1hr.ctl
gribmap -i sst1hr.ctl
で、grads ctlファイルとindexファイル
sst1hr.ctl
ocnsst.gdas.200112.grb2.idx
ができる。水平分解能は0.5x0.5になっていた。
gradsで最初のステップをプロットすると、こんなかんじ
0N, 180Eの最初の48ステップをプロットすると
6時間ごとに値が飛んでいるように見えるのは、6時間ごとに同化(3D-VAR)で解析値に修正していることにともなうものであろう。
grads形式に変換する時に、解析値だけ取り出すには"-0"(ハイフンゼロ)をつけて
g2ctl -0 ocnsst.gdas.200112.grb2 > sst1hr.ctl
gribmap -0 -i sst1hr.ctl
この場合、0N, 180Eの最初の8ステップ(6時間ごとなので、48時間分)をプロットすると
2012年7月24日火曜日
浦神と串本の日平均潮位差をpandasで
以前書いた、pandasでの時系列処理の続き。バージョンアップ(これを書いてる時点でversion 0.8.1)により、さらに便利になった。
浦神と串本の日平均潮位差をプロットしてみる。前回のようにwebから直接読むこともできるが、今回はhttp://www.data.kishou.go.jp/db/kobe/kuroshio/chouisa/chouisa.datからchouisa.datをダウンロードしてそれを読むことにする。
下がプログラム。
read_psvでデータを読んでいる。
前回は日付とデータの間にあるスペースをスマートに処理できなかったが、sep='\s*' (任意の数のスペース)を使えばよかったらしい。
column=0(右端)をindexとして用い(index_col=0)、日付データとして解釈する(parse_dates=Trule)。
”-”を欠損値と解釈する。
version 0.8以降、月平均を計算するのが簡単になり、data.resample("M",how='mean')で良い。
前回は日付とデータの間にあるスペースをスマートに処理できなかったが、sep='\s*' (任意の数のスペース)を使えばよかったらしい。
column=0(右端)をindexとして用い(index_col=0)、日付データとして解釈する(parse_dates=Trule)。
”-”を欠損値と解釈する。
version 0.8以降、月平均を計算するのが簡単になり、data.resample("M",how='mean')で良い。
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
# read data
data=pd.read_csv("chouisa.dat",sep='\s*',skiprows=1,header=None,index_col=0,parse_dates=True,names=("date","chouisa"),na_values="-")
#monthly value
data2=data.resample("M",how='mean')
#plot
plt.subplot(111)
data["chouisa"].plot(style='b-',label="Daily")
data2["chouisa"].plot(style='r-',label="Monthly",linewidth=2)
plt.legend(loc='best')
plt.savefig("choisa.png")
plt.show()
2012年3月16日金曜日
黒潮の流路をpandasで
以前、気象庁黒潮の流軸の緯度のデータをネットから読み込んでプロットしてみた。
同じことをpandas (Python Data Analysis Library)で行ってみる。
import numpy as np
from pandas import *
import matplotlib.pyplot as plt
ds = np.DataSource(None)
f=ds.open('http://www.data.kishou.go.jp/kaiyou/shindan/b_2/kuroshio_stream/kuro_slat.txt')
data=read_csv(f,sep=" ",names=("space","val"),parse_dates=True)
f.close()
data["val"].plot()
plt.xlabel("YEAR")
plt.ylabel("Kurosho latitude")
plt.savefig("pandas_example.png")
(注記) 上のデータ読み込みでは、元データがスペースを使っている関係で、"space"という余計なデータ列(column)を作ってしまう。もっとスマートな方法があるかもしれない。
(追記:2012/7/23) 後日、改良版を書いた。
2011年5月6日金曜日
気象庁全球数値予報モデルGPV (GSM)
気象庁全球数値予報モデルGPV (GSM) の初期値データを京都大学のサイトからダウンロードして、清水慎吾さん作成のgsm2binでgrib2形式からgrads形式に変換するモジュール。
以下がそのモジュール。サンプルのメインプログラムでは、2011年1月1日6時のデータを変換し、python interface to gradsで海面気圧をプロットしている。
get_gsm.py
def get_gsm(date=[2011,1,1,0],dir="."):
"""
download jma gsm initial data from http://database.rish.kyoto-u.ac.jp/arch/jmadata/da
ta/gpv/original/
and
convert to grads file using gsm2bin by Dr. Shingo Shimizu
(http://shimizus.hustle.ne.jp/wiki/wiki.cgi?page=%A5%E2%A5%C7%A5%EB%B4%D8%CF%A2%A5%E1%A
5%E2)
usage:
get_gsm(date,dir)
input
date: [year,month,day,hour] hour must be multiple of 6
default [2011,1,1,0]
dir : directory to save data
"""
import os,urllib
#check
assert date[3] % 6 ==0, "Error, hour must be multiple of 6!!!"
#names from date
urldir,original,gradsbinname,gradsdate=name_maker(date)
# get original data
if not os.path.exists(dir+"/"+original):
if not os.path.exists(dir): os.mkdir(dir)
# Download the data
print 'Downloading data, please wait'
opener = urllib.urlopen(urldir+original)
open(dir+"/"+original, 'w').write(opener.read())
print 'Downloaded'
# convert to grads file
os.system("gsm2bin %(dir)s/%(original)s %(dir)s/%(gradsbinname)s" %locals())
# make ctlfile
make_ctl(dir,gradsbinname,gradsdate)
############################################
def name_maker(date):
"""
make filenames from date
"""
import datetime
time=datetime.datetime(*date)
cyear=time.strftime("%Y")
cmonth=time.strftime("%m")
cmonth2=(time.strftime("%b")).lower()
cday=time.strftime("%d")
chour=time.strftime("%H")
# URL of original data
urldir="http://database.rish.kyoto-u.ac.jp/arch/jmadata/data/gpv/original/%(cyear)s/%(
cmonth)s/%(cday)s/" %locals()
# File name of original data
original="Z__C_RJTD_%(cyear)s%(cmonth)s%(cday)s%(chour)s0000_GSM_GPV_Rgl_FD0000_grib2.
bin" %locals()
# grads bin name after conversion
gradsbinname="gsm%(cyear)s%(cmonth)s%(cday)s%(chour)s.bin" %locals()
# date in grads format
gradsdate="%(chour)s:00Z%(cday)s%(cmonth2)s%(cyear)s" %locals()
return urldir,original,gradsbinname,gradsdate
###########################################
def make_ctl(dir,gradsbinname,gradsdate):
"""
make grads ctl file for GSM data
"""
#ctl file text
ctltxt="""
dset ^%(gradsbinname)s
options template
undef -999
xdef 720 LINEAR 0.0 0.5
ydef 361 LINEAR -90.0 0.5
zdef 17 LEVELS 1000 925 850 700 600 500 400 300 250 200 150 100 70 50
30 20 10
tdef 1 LINEAR %(gradsdate)s 6hr
vars 16
slp 0 0 sea level pressure
sp 0 0 surface pressure
su 0 0 surface westerly wind
sv 0 0 surface southerly wind
st 0 0 surface temperature
srh 0 0 surface relative humidity
lca 0 0 LowCloudAmount
mca 0 0 MidCloudAmount
hca 0 0 HighCloudAmount
tca 0 0 TotalCloudAmount
z 17 0 height
u 17 0 westerly wind
v 17 0 southerly wind
t 17 0 temperature
rh 17 0 relative humidity
w 17 0 p-velocity
endvars
"""
# write to file
gradsctlname=dir+"/"+gradsbinname.replace(".bin",".ctl")
f=open(gradsctlname,"w")
f.write(ctltxt %locals())
f.close()
#-----------------------------------------------------------------------
if __name__ == '__main__':
# get gsm data
get_gsm(date=[2011,1,1,6],dir="DATA")
# plot
from grads.galab import GaLab # for python interface for grads
ga = GaLab(Bin='grads',Window=False,Echo=True,Verb=0,Port=False)
ga.open("DATA/gsm2011010106.ctl")
script="""
set grads off
set gxout shaded
d slp/100
cbarn
draw title Sea level pressure (hpa)
printim gsm.png white
"""
ga(script)
2011年3月5日土曜日
気象庁MGDSST
気象庁の海面水温データ(0.25x0.25度、daily)であるMGDSSTをウェブからダンロードしてから、データを読み込むまでのモジュールをつくる。MGDSSTはNEAR-GOOSのサイトから入手が可能である。
idとpasswordが必要なので、あらかじめ登録しておく。
以下がスクリプト
usrname="xxxxx"
password="*****"
のところを自分のidとpasswordで置き換える。
import numpy as np
import os
def downloadfile(infile="remotefile",outfile="localfile"):
"""
download file from NEAR-GOOS data site with id and password
input
infile: remote file on the web
outfile: local file
set password and id below
"""
import urllib2
host="goos.kishou.go.jp:80"
realm="NEAR-GOOS"
usrname="xxxxx"
password="*****"
auth_handler = urllib2.HTTPBasicAuthHandler()
auth_handler.add_password(realm, host, usrname, password)
opener = urllib2.build_opener(auth_handler)
urllib2.install_opener(opener)
f=urllib2.urlopen(infile)
open(outfile, 'w').write(f.read())
#----------------------------------------------------------
def readMGDSST(dir=".",year=2010,month=1,day=1,lonrange=(0,360),latrange=(-90,90)):
"""
load MGDSST data from NEAR-GOOSE site
read data with fortran (f2py)
select region specified by lonrange and latrange
Usage:
lon,lat,sst= readMGDSST(dir=".",year=2010,month=1,day=1,lonrange=(0,360),latrange=(-90,90)
Input
dir: directory for data download
year,month,day: date of the data
lonrange,latrange = longitude and latitude range for data
output
lon, lat: longitude, latitude
sst: sst data
"""
# date
import datetime
t=datetime.datetime(year,month,day)
syear=t.strftime("%Y")
smon=t.strftime("%b")
sday=t.strftime("%d")
# filename
dataname="mgdsst."+smon+sday
filename=dir+"/"+dataname+"."+syear
filenamegz=filename+".gz"
print filename
urlname="http://goos.kishou.go.jp/rrtdb/usr/pub/JMA/mgdsst/"+syear+"/"+dataname+".gz"
# file exist?
if not os.path.exists(filename):
if not os.path.exists(filenamegz):
downloadfile(infile=urlname,outfile=filenamegz)
os.system("gunzip %(filenamegz)s" %locals())
# temp.bin is used for temporary file
if os.path.lexists("temp.bin"):
raise IOError("temporary file temp.bin somehow exist! Remove it!")
else:
os.system("ln -s %(filename)s temp.bin" %locals())
# data read through fortran (f2py)
from read_sst import read_sst
im=1440
jm=720
sst=np.zeros([jm,im])
sst,ierr=read_sst()
assert ierr==0, "data error in fortran"
lon=0.125+0.25*np.arange(im)
lat=-89.875+0.25*np.arange(jm)
os.system("rm temp.bin")
# range selection
xrange=np.logical_and(lon>=lonrange[0],lon<=lonrange[1])
yrange=np.logical_and(lat>=latrange[0],lat<=latrange[1])
sst=(sst[yrange,:])[:,xrange]
return lon[xrange],lat[yrange], sst
#-----------------------------------------------------------------------
if __name__ == '__main__':
import cdms2,MV2,vcs #cdat
# read data
lon,lat,sst=readMGDSST(dir="DATA",year=2011,month=1,day=1,lonrange=(0,360),latrange=(-90,90))
# hearafter plot with cdat
# First let's create a variable
var = MV2.masked_array(sst,mask=(sst<-990.),id="SST")
# Now create the axis
lons=cdms2.createAxis(lon)
lats=cdms2.createAxis(lat)
# And decorate it
lons.id = 'longitude'
lats.id = 'latitude'
lons.units = 'degrees_east'
lats.units = 'degrees_north'
# Just to make sure we will describe this axis as a longitude one
lons.designateLongitude()
lats.designateLatitude()
# Now let's apply these to the variable
var.setAxisList((lats,lons))
#var.info() to see info
#plot
v = vcs.init()
v.plot(var)
v.png("MGDSST.png")
del v
上のサンプルメインプログラムでは、2011年1月1日のデータをディレクトリ"DATA"にダウンロードし、経度0から360度、緯度-90度から90度の範囲で読み込んでいる。
その上で、cdatを用いて可視化した。
結果は以下の図。
ダウンロードしたバイナリファイルを読むのにfortranのプログラムをモジュールとしてつかう。清水慎吾さんのデータを読むサンプルプログラムを参考に、以下のようなfortranサブルーチンを作った(配列はpython風に緯度と経度を入れ替えている。欠損値は-999.)。
このプログラムをf2pyを使って以下のようにコンパイルすればpythonのモジュールとして使用が可能になる(上のプログラムのread_sst)。
f2py --f90exec=gfortran -c -m read_sst read_sst.f90
(ここではgfortranを使っている。)
read_sst.f90
subroutine READ_SST(sst,ierr)
implicit none
integer :: year,mon,day
integer :: i,j,jj
integer,parameter :: im=1440
integer,parameter :: jm=720
!
real,intent(out):: sst(jm,im)
integer, intent(out):: ierr
!
integer :: isst(im,jm),ist
real :: undef = -999.
open(55,file="temp.bin",status='old',form='formatted',iostat=ierr,err=999)
read(55,*) year,mon,day
write(6,*) year,mon,day
do j=1,jm
read(55,10,iostat=ierr,err=999) (isst(i,j),i=1,im)
enddo
close(55)
10 format(1440i3)
do j=1,jm
do i=1,im
jj = jm -j +1
ist = isst(i,jj)
if(ist .eq. 888 .or. ist.eq.999) then
sst(j,i) = undef
else
sst(j,i) = real(ist)*0.1
endif
enddo
enddo
return
999 print *, "Read Error!"
end subroutine READ_SST
2011年2月25日金曜日
Gradsでregrid
GrADSにおいて、二つのデータセットのグリッドをそろえて、差を見てみることをおこなった。
OpenGrADSのre関数を用いた。
下のソース例、
define sstre=re(sst.1,180,linear,0,2,89,linear,-88,2,ba)
では、変数sst.1を
経度方向に、180グリッド、0度から2度刻みで、線形
緯度方向に、89グリッド、南緯88度から2度刻みで、線形
box averageでグリッドに落としている。
例ではNOAA OISST version 2(1)とNOAA Extended Reconstructed SST version 3b(2)という二つの1月の海面水温データセットから2011年1月の値をそれぞれプロットし、3番目の図で、その差(2-1)を引いている。データはNOAAのサイトからOPeNDAPで取得している。
下がgradsのスクリプト。
"grads -p"でportraitモードで使う。
他に、mul.gs, color.gs, draws.gs という Chihiro Kodama氏のgradsスクリプトを用いている。
"reinit" *NOAA OISST V2 "sdfopen http://www.esrl.noaa.gov/psd/thredds/dodsC/Datasets/noaa.oisst.v2/sst.m nmean.nc" "set time jan2011" "mul 1 3 1 3 -yoffset -0.5" "set grads off" "color 0 30 2 -kind grainbow -gxout grfill" "d sst" "set strsiz 0.15" "draws 1) NOAA OISST V2" *NOAA Extended Reconstructed SST V3b "sdfopen http://www.esrl.noaa.gov/psd/thredds/dodsC/Datasets/noaa.ersst/sst.mnme an.nc" "set time jan2011" "mul 1 3 1 2 -yoffset -0.5 " "set grads off" "color 0 30 2 -kind grainbow -gxout grfill" "d sst.2" "set strsiz 0.15" "draws 2) NOAA Extended Reconstructed SST V3b" "cbarn 0.7 1 7.6 7.5" *diff "define sstre=re(sst.1,180,linear,0,2,89,linear,-88,2,ba)" "mul 1 3 1 1 -yoffset -0.5" "set grads off" "color -levs -2 -1.5 -1 -0.5 0.5 1.0 1.5 2 -kind blue->white->red -gxout grfill" "d sst.2-sstre" "set strsiz 0.15" "draws 2)-1)" "cbarn 0.7 1 1. 2." "printim sst_regrid_compare.png white"
2010年12月17日金曜日
気象庁全国合成レーダー降雨
気象庁の全国合成レーダー降雨データがこちらで配布されている。
データは10分ごとにある。
データはtarでアーカイブされており、その中に含まれるデータはgrib2形式である。
清水慎吾さんがこちらで、データをgrads形式に変換するプログラムを公開している(全国合成気象庁レーダ雨量,GRIB2形式)。
以下のプログラムはファイルをネットから読み込んで、清水さんのツールでgrads形式に変換するpythonスクリプトである。
RadarToGradsはファイル(tarファイル)をネットから呼んで、tarファイルから降雨データのバイナリファイル(grib2)を取り出し、gradsファイルを作る。
grib2からgradsへのファイル変換は清水さんのjmaradar2binで行っている。gradsコントロールファイル("view_radar.ctl")が自動的にできるようにmain.cで"gradsout=1"としている。
PlotByGradsは作ったgradsデータを使って、gradsでプロットしている。gradsを操作するのに、pythonインターフェイスを使っている。
メインでは、これらを使って、2010年10月20日午前8時00分世界標準時(日本時間午後5時)の降水を東経125-135度北緯24-35度でgradsデータに変換して、それをプロットしている。これは奄美大島で豪雨が発生したころにあたる。
import_jmaradar.py
def RadarToGrads(dir=".",gradsbinname="temp.bin",year=2010,mon=1,day=1,hour=0,mi
n=0,slon=118.,elon=150.,slat=20.,elat=48.):
"""
Import JMA rain radar data (every 10min) from http://database.rish.kyoto-u.ac
.jp/arch/jmadata/synthetic-original.html
Then convert data to grads file using tool by Dr. Shingo Shimizu (http://shim
izus.hustle.ne.jp/wiki/wiki.cgi?page=%A5%EC%A1%BC%A5%C0%B4%D8%CF%A2%A5%E1%A5%E2)
usage:
RadarToGrads(dir=".",gradsbinname="temp.bin",year=2010,mon=1,day=1,hour=0
,min=0,slon=118.,elon=150.,slat=20.,elat=48.):
input
dir: directory to import tar file
gradsbinname: file name for grads binary
year, mon, day, hour, min : time for data (every 10 min) in UTC
slon,elon Western,East bounday
slat,elat South,North bounday
output files
grads binary: gradsbinname
grads control: view_radar.ctl
"""
import os
import tarfile
import urllib
# filenames
syear="%04d" % year
smon="%02d" % mon
sday="%02d" % day
shour="%02d" % hour
smin="%02d" % min
date=syear+smon+sday+shour+smin
tarname="Z__C_RJTD_%(date)s00_RDR_JMAGPV__grib2.tar" %locals()
urldir="http://database.rish.kyoto-u.ac.jp/arch/jmadata/data/jma-radar/synth
etic/original/%(syear)s/%(smon)s/%(sday)s/" %locals()
filename="Z__C_RJTD_%(date)s00_RDR_JMAGPV_Ggis1km_Prr10lv_ANAL_grib2.bin" %l
ocals()
# get tar file
if not os.path.exists(dir+"/"+tarname):
if not os.path.exists(dir): os.mkdir(dir)
# Download the data
print 'Downloading data, please wait'
opener = urllib.urlopen(urldir+tarname )
open(dir+"/"+tarname, 'w').write(opener.read())
print 'Downloaded'
# extract radar precipitation file
tarfile.open(dir+"/"+tarname, 'r').extract(filename)
# convert to grads file
os.system("jmaradar2bin %(filename)s %(gradsbinname)s %(slon)s %(elon)s %(sl
at)s %(elat)s" %locals())
os.system("rm %(filename)s" %locals())
####################################################################
def PlotByGrads(pngname):
"""
plot converted JMA radar rain data
"""
from grads.galab import GaLab # for python interface for grads
ga = GaLab(Bin='grads',Window=False,Echo=False,Verb=0,Port=False)
ga.open("view_radar.ctl")
script="""
set grads off
set mpdset hires
set gxout shaded
set clevs 0 1 5 10 20 30 50 80
d rr
cbarn
printim %(pngname)s white
"""
ga(script %locals())
#####################################################################
if __name__ == '__main__':
# radar file to grads
RadarToGrads(dir="DATA",gradsbinname="jmaradar.bin",year=2010,mon=10,day=20,
hour=8,min=00,slon=125.,elon=135.,slat=24.,elat=35.)
# plot by grads
PlotByGrads("jmaradar.png")
2010年10月1日金曜日
富士山の初冠雪日(1) データ取得
甲府気象台のwebページ表から、富士山初冠雪日を取得するプログラムを作る。
以下がプログラム。
関数 read_FirstSnowFuji()が初冠雪日を取得するモジュールで、年、月、日をnumpyの配列として返す。HTMLから表を読むのにtable parserを用いている。
メインプログラムでは、日付をscikits.timeseriesで年初からの日にち(1月1日を1とする)に変換し、グラフにしている。平均値を黒い実線で、平均値から標準偏差(約14日)の2倍離れた値に黒点線を引いた。ばらつきがかなり大きい印象だ。今年は少しだけ平年より早い。
read_FirstSnowFuji.py
import numpy as np
# table parser from http://simbot.wordpress.com/2006/05/17/html-table-parser-using-python/
from table_parser import *
def read_FirstSnowFuji():
import urllib
"""
read first snow cover day of the FUJI mountain from KOFU local meteorological observatory
usage:
year,month,day=read_FirstSnowFuji()
input
none
output
year,month,day: first snow cover day (numpy array)
"""
f = urllib.urlopen('http://www.jma-net.go.jp/kofu/menu/siryo_hatsukansetsu.dat.html')
p = TableParser()
p.feed(f.read())
f.close()
data=p.doc # Get to the data
#get
year=[[],[],[]] # 3 column
month=[[],[],[]] # 3 column
day=[[],[],[]] # 3 column
for d in data[0][1:]:
for n,c in enumerate([0,4,8]):
if not d[c]=="":
year[n].append(int(d[c]))
mi,di=d[c+1].split("/")
month[n].append(int(mi))
day[n].append(int(di))
# to numpy array
ayear=np.array([],dtype="i4")
amonth=np.array([],dtype="i4")
aday=np.array([],dtype="i4")
for n in range(3):
ayear=np.append(ayear,year[n])
amonth=np.append(amonth,month[n])
aday=np.append(aday,day[n])
return ayear,amonth,aday
############################################
if __name__ == '__main__':
import matplotlib.pyplot as plt
import scikits.timeseries as ts
ayear,amonth,aday= read_FirstSnowFuji()
days=np.array([],dtype="i4")
for n in range(ayear.size):
td=ts.Date("D",year=ayear[n],month=amonth[n],day=aday[n])
days=np.append(days,td.day_of_year)
#plot
plt.plot(ayear,days,"b-")
mean=days.mean()
stdp=days.mean()+2*days.std()
stdm=days.mean()-2*days.std()
plt.plot([ayear[0],ayear[-1]],[mean,mean],"k-")
plt.plot([ayear[0],ayear[-1]],[stdp,stdp],"k--")
plt.plot([ayear[0],ayear[-1]],[stdm,stdm],"k--")
plt.xlim(ayear[0],ayear[-1])
plt.xlabel("year")
plt.ylabel("day of year")
plt.savefig("FujiFirstSnow.png")
plt.show()
2010年9月25日土曜日
TRMM 3B42 降水データ
人工衛星TRMMの降水データ3B42をプロットする。
この降水データは水平分解能0.25度で3時間ごとにデータがある。
このデータをNASA MiradorからOPeNDAPを通して入手する。
以下の例は7月27日0時世界標準時(日本標準時9時)の日本付近のデータをプロットする例である。この日は東シナ海に熱帯低気圧が存在し、それによる雨が見える。
OPeNDAPからはPyNIOを使ってデータを入手する。
関数name_makerはファイルのあるURLはこういう規則だろうと推測して作ったものである。間違いかもしれないので確認すること。
参考
NASA Giovanniのサイト
http://disc2.nascom.nasa.gov/Giovanni/tovas/TRMM_V6.3B42.2.shtml
TRMM 3B42 readme
ftp://meso-a.gsfc.nasa.gov/pub/trmmdocs/3B42_3B43_doc.pdf
この降水データは水平分解能0.25度で3時間ごとにデータがある。
このデータをNASA MiradorからOPeNDAPを通して入手する。
以下の例は7月27日0時世界標準時(日本標準時9時)の日本付近のデータをプロットする例である。この日は東シナ海に熱帯低気圧が存在し、それによる雨が見える。
OPeNDAPからはPyNIOを使ってデータを入手する。
関数name_makerはファイルのあるURLはこういう規則だろうと推測して作ったものである。間違いかもしれないので確認すること。
import Nio
import numpy as np
def read_TRMM_3B42(date,lon1,lon2,lat1,lat2):
"""
read TRMM 3B42 3 hourly rainfall from NASA Mirador
usage:
lon,lat,sst=read__TRMM_3B42(date,lon1,lon2,lat1,lat2)
input
date (year,month,day,hour)
lon1,lon2 Western,East bounday
lat1,lat2 South,West bounday
output
lon longitude
lat latitude
rainfall data (mm/hour)
"""
#check
assert date[3] % 3 ==0, "Error, hour must be multiple of 3!!!"
# open OPENDAP
fname=name_maker(date[0],date[1],date[2],date[3])
f = Nio.open_file(fname)
## variable name check
#variables = f.variables.keys()
#print f
#print "variables",variables
# read data
temp=f.variables["DATA_GRANULE.PlanetaryGrid.precipitation"]
#grid
# grid
lon=-179.875+np.arange(temp.shape[1])*0.25
lat=-49.875 +np.arange(temp.shape[2])*0.25
# selection
xrange=np.where(np.logical_and(lon>=lon1,lon<=lon2))
yrange=np.where(np.logical_and(lat>=lat1,lat<=lat2))
#precipitation
x=xrange[0]
y=yrange[0]
precip=(temp[0,x[0]:x[-1]+1,y[0]:y[-1]+1].T).reshape((len(y),len(x)))
# closing
f.close()
return lon[xrange],lat[yrange],precip
############################################
def name_maker(year,month,day,hour):
import scikits.timeseries as ts
#
t=ts.Date('H', year=year,month=month,day=day,hour=hour)
if t.hour==0:
tc=t-1
else:
tc=t
cyear = "%04d" % tc.year
cyear2= "%02d" % (t.year-2000)
cmonth2= "%02d" % t.month
cday2= "%02d" % t.day
shour = str(t.hour)
yd3= "%03d" % tc.day_of_year
#
fname="http://disc2.nascom.nasa.gov/opendap/TRMM_L3//TRMM_3B42//%(cyear)s/%(yd3)s/3B42.%(cyear2)s%(cmonth2)s%(cday2)s.%(shour)s.6A.HDF.Z" %locals()
return fname
############################################
if __name__ == '__main__':
import matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap
# example plot
# range
lon1=120.
lon2=145.
lat1=20.
lat2=40.
#date
year=2009
month=7
day=27
hour=0
lon,lat,precip=read_TRMM_3B42(date=(year,month,day,hour),lon1=lon1,lon2=lon2,lat1=lat1,lat2=lat2)
#plot
vmax=int(precip.max())
vmin=int(precip.min())
fig=plt.figure()
ax = fig.add_axes([0.1,0.1,0.8,0.8])
map = Basemap(projection='merc',llcrnrlat=lat1,urcrnrlat=lat2,\
llcrnrlon=lon1,urcrnrlon=lon2,resolution='i')
lons,lats=np.meshgrid(lon[:],lat[:])
x,y=map(lons,lats)
map.drawcoastlines()
map.drawmapboundary()
map.pcolor(x,y,precip,vmin=vmin,vmax=vmax,cmap=plt.cm.Blues)
ti=str(year)+"/"+str(month)+"/"+str(day)+":"+str(hour)+"Z"
plt.title(ti)
# colorbar
pos = ax.get_position()
l, b, w, h = pos.bounds
cax = plt.axes([l+w+0.02, b, 0.03, h]) # setup colorbar axes.
plt.colorbar(cax=cax) # draw colorbar
plt.savefig("TRMM_3B42.png")
plt.show()
参考
NASA Giovanniのサイト
http://disc2.nascom.nasa.gov/Giovanni/tovas/TRMM_V6.3B42.2.shtml
TRMM 3B42 readme
ftp://meso-a.gsfc.nasa.gov/pub/trmmdocs/3B42_3B43_doc.pdf
2010年9月4日土曜日
EORC MODIS SST
JAXA EORC提供のMODIS SSTをプロットするスクリプトを作成した。
データのバイナリはEORCに提供していただいた。
下の例ではは2010年8月2日の領域6のデータから紀伊半島付近をプロットしている。 A2GL11008020431OD1_OSTAQ_01000_01000_sst_06
ファイルのフォーマットの情報はここ。
import numpy as np
def read_MODIS_EORC(file,lon1,lon2,lat1,lat2):
"""
read MODIS_SST from EORC
usage:
lon,lat,sst=read_MODIS_EORC(file,lon1,lon2,lat1,lat2)
input
file filename
lon1,lon2 Western,East bounday
lat1,lat2 South,West bounday
output
lon longitude
lat latitude
SST sst data (masked array) in C
"""
# open file
f=open(file, 'r')
# read header
pixel=f.read(6); print "pixel=",pixel
line=f.read(6); print "line=",line
nwlon=f.read(8); print "NW lon.=",nwlon
nwlat=f.read(8); print "NW lat.=",nwlat
res=f.read(8); print "resolution=",res
slope=f.read(9); print "slope=",slope
offset=f.read(9); print "ofset=",offset
dummy=f.read(1)
parameter=f.read(8); print "parameter name=",parameter
dummy=f.read(1)
filename=f.read(45); print "file name=",filename
f.close()
# read data
f=open(file,'r')
f.seek(int(pixel)*2) #skip header
data=np.fromfile(f,dtype=">u2")
data=data.reshape((int(line),int(pixel)))
msk=np.logical_or(data==0,data>=65534) # 0 cloud, 65534 out of obs., 65535 land
data=np.ma.masked_array(data[::-1],mask=msk[::-1,:])
data=data*float(slope)+float(offset)-273.15 # to degree C
f.close()
# grid
lon=float(nwlon)+np.arange(int(pixel))*float(res)
lat=float(nwlat)-np.arange(int(line))*float(res)
lat=lat[::-1]
# selection
xrange=np.logical_and(lon>=lon1,lon<=lon2)
yrange=np.logical_and(lat>=lat1,lat<=lat2)
sst=(data[yrange,:])[:,xrange]
return lon[xrange],lat[yrange], sst
############################################
if __name__ == '__main__':
import matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap
# example plot
#read data
filename="A2GL11008020431OD1_OSTAQ_01000_01000_sst_06"
lon1=135.
lon2=138.
lat1=32.
lat2=35.
lon,lat,sst=read_MODIS_EORC(filename,lon1,lon2,lat1,lat2)
#plot
tmax=int(sst.max())
tmin=int(sst.min())
fig=plt.figure()
ax = fig.add_axes([0.1,0.1,0.8,0.8])
map = Basemap(projection='merc',llcrnrlat=lat1,urcrnrlat=lat2,\
llcrnrlon=lon1,urcrnrlon=lon2,resolution='i')
lons,lats=np.meshgrid(lon[:],lat[:])
x,y=map(lons,lats)
map.drawcoastlines()
map.drawmapboundary()
map.pcolor(x,y,sst,vmin=tmin,vmax=tmax)
# colorbar
pos = ax.get_position()
l, b, w, h = pos.bounds
cax = plt.axes([l+w+0.02, b, 0.03, h]) # setup colorbar axes.
plt.colorbar(cax=cax) # draw colorbar
plt.savefig("MODIS_EORC_SST.png")
plt.show()
謝辞
ここで用いたSSTバイナリは宇宙航空研究開発機構(JAXA)地球観測研究センター(EORC)から提供されたものである。ここに感謝する。
関連ポスト
MODIS aqua Global Level 3 Mapped Mid-IR SST (4km)
http://oceansciencehack.blogspot.com/2010/09/modis-aqua-global-level-3-mapped-mid-ir.html
参考
MODIS EORC SST FAQ
http://kuroshio.eorc.jaxa.jp/ADEOS/mod_nrt_new/html/05_faq.html
JAXA MODISページ
http://www.eorc.jaxa.jp/hatoyama/satellite/sendata/modis_j.html
MODIS wikipedia
http://ja.wikipedia.org/wiki/MODIS
2010年9月3日金曜日
CEReS NOAA/AVHRR SST
CEReSで配布しているNOAA AVHRR SSTをプロットしてみた。
FTPサイトからデータをダウンロードして、解凍する。
ここでは n1810080316.sst.giを利用する。
(NOAA 18 ,2010年,8月3日,16世界標準時)
以下がスクリプト。
このデータには雲や陸地のマスクはないようだ。
前回はPyNGLでプロットしたが、今回はmatplotlib basemap toolkitを利用した。
matlabのpplot関数に対応する関数を使いたかったからだ(PyNGLにはあるのかな?)。
import numpy as np
import matplotlib.pyplot as plt
def read_CEReS_SST(dir,file,lon1,lon2,lat1,lat2):
"""
read CERes SST
usage:
lon,lat,sst=read_CEReS_SST(dir,file,lon1,lon2,lat1,lat2)
input
dir working dir
file filename
gzipped file is fine.
URL also works
lon1,lon2 Western,East bounday
lat1,lat2 South,West bounday
output
lon longitude
lat latitude
SST sst data (masked array) in C
"""
# read data
ds=np.DataSource(dir)
f=ds.open(file, 'r')
f.seek(80) # skip header
ssttemp=np.frombuffer(f.read(),dtype=">i2",count=6378*5562)
f.close()
# as masked array
sst=ssttemp.reshape((5562,6378))*0.1
sst=np.ma.masked_array(sst[::-1,:],mask=(sst[::-1,:]==0 ))
# grid
lon=100.+np.arange(6378)*0.01097869
lat=9.97971+np.arange(5562)*0.00899322
# selection
xrange=np.logical_and(lon>=lon1,lon<=lon2)
yrange=np.logical_and(lat>=lat1,lat<=lat2)
sst=(sst[yrange,:])[:,xrange]-273.15 # Kelvin to C
return lon[xrange],lat[yrange], sst
############################################
if __name__ == '__main__':
from mpl_toolkits.basemap import Basemap
# example plot
#read data
filename="n1810080316.sst.gi"
lon1=130.
lon2=140.
lat1=30.
lat2=36.
lon,lat,sst=read_CEReS_SST(".",filename,lon1,lon2,lat1,lat2)
#plot
tmax=30.
tmin=20.
fig=plt.figure()
ax = fig.add_axes([0.1,0.1,0.8,0.8])
map = Basemap(projection='merc',llcrnrlat=lat1,urcrnrlat=lat2,\
llcrnrlon=lon1,urcrnrlon=lon2,resolution='i')
lons,lats=np.meshgrid(lon[:],lat[:])
x,y=map(lons,lats)
map.drawcoastlines()
map.drawmapboundary()
map.pcolor(x,y,sst,vmin=tmin,vmax=tmax)
# colorbar
pos = ax.get_position()
l, b, w, h = pos.bounds
cax = plt.axes([l+w+0.02, b, 0.03, h]) # setup colorbar axes.
plt.colorbar(cax=cax) # draw colorbar
plt.savefig("CEReS_SST.png")
plt.show()
登録:
投稿 (Atom)






















