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において、二つのデータセットのグリッドをそろえて、差を見てみることをおこなった。

OpenGrADSre関数を用いた。
下のソース例、
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"




2011年2月18日金曜日

GaLab in Python Interface to GrADS



Python Interface to GrADSGaLabを用いてプロットしてみた。
プロットしたデータはEarth System Research Laboratoryで配布されているNCEP/NCAR再解析の2011年1月の海水面気圧をOPeNDAPで取得している。

import matplotlib.pyplot as plt
from grads.galab import GaLab  # for python interface for grads

ga = GaLab(Bin='grads',Window=False,Echo=True,Verb=0,Port=False)

ga.open("http://www.esrl.noaa.gov/psd/thredds/dodsC//Datasets/ncep.reanalysis.de
rived/surface/slp.mon.mean.nc")

ga.blue_marble("on")
ga("set time jan2011")
ga.basemap('ortho',opts=(130.,40.))

ga.contour("slp")
del ga
plt.title("Sea Level Pressure (Jan2011)")
plt.savefig("galab_slp.png")

Matplotlib Basemap Toolkitよりも手軽にプロットできる半面、緯度・経度線を取り除いたりとかの自由はききにくいようだ。

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年11月7日日曜日

Google Graphで棒グラフ



GE-GraphというGoogle Graph上に棒グラフをプロットできるフリーソフトがある。 http://www.sgrillo.net/googleearth/gegraph.htm
これを使ってみた。

結果から。下の図は正味海洋-大気熱フラックス(海から大気)の1月長期平均をGoogle Earth上で棒グラフにしたものである。正値のみ使っている。
このkmzファイルはこちら

GE-Graphに入力するデータとして
場所名,緯度,経度,値
で構成されるcsvファイルを用意する必要がある。
上の例のcsvファイルはコレ(その1,その2
GE-Graphが5000地点以上を受け付けないのでファイルを2つに分けている。場所名は特に意味は無いので全て0を入れている。

上のデータをGE-Graphに読み込ませる。設定は以下の図のようにした。
それぞれのデータで"Run"を行ってkmzファイルを作った。Google Earth上で二つのファイルをまとめて、saveしたのが上のkmzファイルである。

最後にcsvファイルを作るpythonプログラムを添付する。
NCEP/NCARのデータをESRLのサイトからPython Interface to GrADS を使って読み込む。
latent/sensible heat flux, longwave/shortwave radiationを全て足して正味の熱フラックスを計算する。
陸・海マスクを読み、海のデータだけを使う。また正(海から大気)のデータだけ残している。データは4000点づつセーブする。
from grads.ganum import GaNum  # for python interface for grads
import numpy as np

#====== DATA read
ga = GaNum(Bin='grads')
ga("sdfopen http://www.esrl.noaa.gov/psd/thredds/dodsC/Datasets/ncep.reanalysis.derived/surface_gauss/lhtfl.mon.ltm.nc") #net latent heat flux
ga("sdfopen http://www.esrl.noaa.gov/psd/thredds/dodsC/Datasets/ncep.reanalysis.derived/surface_gauss/shtfl.mon.ltm.nc") #net sensible heart flux
ga("sdfopen http://www.esrl.noaa.gov/psd/thredds/dodsC/Datasets/ncep.reanalysis.derived/surface_gauss/nswrs.mon.ltm.nc") #net shortwave radiation
ga("sdfopen http://www.esrl.noaa.gov/psd/thredds/dodsC/Datasets/ncep.reanalysis.derived/surface_gauss/nlwrs.mon.ltm.nc") #net longwave radiation
ga("set t 1")  # January
ga("netheat=lhtfl.1+shtfl.2+ nswrs.3+nlwrs.4") # all net heat
netheat=ga.exp("netheat")
ga("close 4")
ga("close 3")
ga("close 2")
ga("close 1")
ga("sdfopen http://www.esrl.noaa.gov/psd/thredds/dodsC/Datasets/ncep.reanalysis/surface_gauss/land.sfc.gauss.nc")  #land sea mask
land=ga.exp("land")
del ga

lon=netheat.grid.lon
lat=netheat.grid.lat

#===== DATA manupilation
data=netheat.data
data[land>0]=-999.  # remove values on land

x,y=np.meshgrid(lon,lat)

vl=0.               # data criteria 

xout=x[data>vl].flatten()      # only  values >vl  are used
xout[xout>180]=xout[xout>180]-360. #   -180.=<lon<=180.  
yout=y[data>vl].flatten()      # only  values >vl  are used
zout=data[data>vl].flatten()   # only  values >vl  are used
points=np.zeros(data[data>vl].size) # position number (anythin is ok)

#==== DATA output
nn=zout.size/4000+1
for n in range(nn):
    st=4000*n
    en=4000*(n+1)
    np.savetxt("data%(n)s.txt" %locals(),np.transpose((points[st:en],yout[st:en],xout[st:en],zout[st:en])),fmt='%4i,%7.3f,%7.3f,%7.3f')


2010年10月29日金曜日

Google Earthでアニメーション



以前、Google Earthで図を描いたが、今回はアニメーションを作ってみる。図が3枚だけのアニメーションだ。

手順1
Gradsで図を3枚つくる。GradsでGoogle Earth向きの図をつくるやり方は以前の記事を参照のこと。下の例はNCEP/NCARの最解析データを使って、2008年から2010年の8月の表面大気温度のアノマリをプロットしている。colorbarはxcbarを使って図の上に一緒に乗せた。
"reinit"
"sdfopen http://www.esrl.noaa.gov/psd/thredds/dodsC//Datasets/ncep.reanalysis.de
rived/surface/air.mon.mean.nc"
"sdfopen http://www.esrl.noaa.gov/psd/thredds/dodsC//Datasets/ncep.reanalysis.de
rived/surface/air.mon.ltm.nc"
year=2008
while (year<=2010)
"set time aug"year
"set x 1 144"
"set y 1 73"
"set parea 0 11 0 8.5"
"set grid off"
"set grads off"
"set mproj scaled"
"set mpdraw off"
"set gxout shaded"
"color -5 5 0.5 -kind blue->gray->red"
"d air.1-air.2(t=8)"
"xcbar  4.5 6.5 4 4.2 -edge triangle -fstep 10 "
"printim  airtemp_"year"aug.png x2048 y1024 -t 0"
"c"
year=year+1
endwhile

こんな感じの図ができる。


手順2
基になるkmlファイルをGradsで作成する。やり方は以前の記事と同じだ。
*************KML
"reinit"
"sdfopen http://www.esrl.noaa.gov/psd/thredds/dodsC//Datasets/ncep.reanalysis.de
rived/surface/air.mon.mean.nc"
"set time aug2010"
"set x 1 144"
"set y 1 73"
"set kml airtemp"
"set gxout  kml"
"d air"

以下のようなkmlファイルが出来る。
<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2">
  <GroundOverlay>
    <name>Monthly Mean Air Temperature</name>
    <Icon>
      <href>airtemp.tif</href>
    </Icon>
    <LatLonBox>
      <west>     -1.25</west>
      <east>    358.75</east>
      <south>    -91.25</south>
      <north>     91.25</north>
      <rotation>0.0</rotation>
    </LatLonBox>
  </GroundOverlay>
</kml>

手順3
kmlファイルを以下の様に書き換える。
ポイントは

GroundOverlayから/GraoundOverlayの部分を図の数だけ繰り返す。
・それぞれ図の名前を指定する。
・図がどの時間を占めるべきかTimeSpan /TimeSpanの部分で指定する。なお、今の場合、図は8月だけの図であるが、アニメーションで図が続く様に1年中同じ図が表示されるよう、1月1日から12月31日をTimeSpanで設定している。
・繰り返しの全体をFolder/Folderではさむ。 

<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2">
<Folder>
  <GroundOverlay>
    <name>Monthly Longterm Mean of Air Temperature</name>
    <TimeSpan>
      <begin>2008-01-01</begin>
      <end>  2008-12-31</end>
    </TimeSpan>
    <Icon>
      <href>airtemp_2008aug.png</href>
    </Icon>
    <LatLonBox>
      <west>     -1.25</west>
      <east>    358.75</east>
      <south>    -91.25</south>
      <north>     91.25</north>
      <rotation>0.0</rotation>
    </LatLonBox>
  </GroundOverlay>

  <GroundOverlay>
    <name>Monthly Longterm Mean of Air Temperature</name>
    <TimeSpan>
      <begin>2009-01-01</begin>
      <end>  2009-12-31</end>
    </TimeSpan>
    <Icon>
      <href>airtemp_2009aug.png</href>
    </Icon>
    <LatLonBox>
      <west>     -1.25</west>
      <east>    358.75</east>
      <south>    -91.25</south>
      <north>     91.25</north>
      <rotation>0.0</rotation>
    </LatLonBox>
  </GroundOverlay>

  <GroundOverlay>
    <name>Monthly Longterm Mean of Air Temperature</name>
    <TimeSpan>
      <begin>2010-01-01</begin>
      <end>  2010-12-31</end>
    </TimeSpan>
    <Icon>
      <href>airtemp_2010aug.png</href>
    </Icon>
    <LatLonBox>
      <west>     -1.25</west>
      <east>    358.75</east>
      <south>    -91.25</south>
      <north>     91.25</north>
      <rotation>0.0</rotation>
    </LatLonBox>
  </GroundOverlay>
</Folder>
</kml>

出来たファイルをkmzにまとめたものをこちらに置いた。kmzファイルはkmlと図をまとめたもので、Google Earthで一度kmlファイルを開いて、「名前をつけて保存」で作成できる。

Google Earthで開くとこんな感じ。