概要
2023年も残りわずかということで、今年の天気図をGIFアニメーションで動画化して振り返ってみました。
データの準備
気象庁のサイトでは毎日3時間ごと(日本時間0時除く)の日本周辺域の実況天気図を公開しています。
これらの天気図を使いたいところなのですが、画像のURLパスを見てみると…
https://www.jma.go.jp/bosai/weather_map/data/png/20231128020830_0_Z__C_010000_20231128000000_MET_CHT_JCIspas_JCP600x581_JRcolor_Tjmahp_image.png
となっていました。
最後のスラッシュの後に、日時の情報があるのでこれらを変えれば画像にアクセスできるはずです。
しかし、よくよく見てみるとURLの形式は以下のようになっています。
https://www.jma.go.jp/bosai/weather_map/data/png/ #ここは共通
20231128020830 # 画像をアップした日時(UTC:YYYYMMDDhhmmss)?
_0_Z__C_010000_ # ここも共通
20231128000000 # 天気図の日時(UTC:YYYYMMDDhhmmss)
_MET_CHT_JCIspas_JCP600x581_JRcolor_Tjmahp_image.png # ここも共通
画像のアップロード日時らしきものがURLに入ってしまっているため、これだと難しいですね…1。
そこで、100年天気図データベースという気象庁の天気図をアーカイブしているサイトを使います。
例えば2023年11月28日9時の天気図画像のURLは
http://agora.ex.nii.ac.jp/digital-typhoon/weather-chart/wxchart/202311/SPAS_COLOR_202311280000.png
となっており、/202311/
や202311280000
の部分を書き換えれば他の日時の天気図へもアクセス可能です。
データ取得はPythonで行いました。コード例は以下です。
日本時間の2023年1月1日3時~11月27日21時までの天気図画像を/data/
ディレクトリ内に保存します。
import os
import urllib.request
import urllib.error
import urllib.parse
import time
import datetime
#### 期間を指定 ####
# 開始日時(UTC)
start = datetime.datetime(2022, 12, 31, 18, 0, 0)
# 終了日時(UTC)
end = datetime.datetime(2023, 11, 27, 12, 0, 0)
####################
savedir = './' # データ保存先ディレクトリ
if not os.path.exists(savedir):
os.makedirs(savedir)
d = start
while d <= end:
if d.hour in [0, 3, 6, 9, 12, 18, 21]:
# データ取得先URL
url = f'http://agora.ex.nii.ac.jp/digital-typhoon/weather-chart/wxchart/{d.year}{d.month:02d}/SPAS_COLOR_{d.strftime("%Y%m%d%H%M")}.png'
# ファイル名
basename = os.path.basename(url)
savename = os.path.join(savedir, basename)
# ファイルが存在しない場合のみダウンロード
if not os.path.exists(savename):
try:
urllib.request.urlretrieve(url, savename)
time.sleep(1)
print('downloaded:', basename)
except urllib.error.URLError as e:
print(url)
print(e)
else:
print('file exists:', basename)
d += datetime.timedelta(hours=3)
GIFアニメーションの作成
Anthropicが開発したAIチャット「Claude」に、GIFの作り方を聞いたら一発で動きました。
Claudeの回答コードで.save()
の引数を若干いじったものを、下に載せておきます。
from PIL import Image
import glob
frames = []
imgs = glob.glob("./data/*.png")
for i in imgs:
new_frame = Image.open(i)
frames.append(new_frame)
frames[0].save('animation.gif', format='GIF', append_images=frames[1:], save_all=True, duration=50, loop=0, optimize=True)
そして、出来上がったGIFアニメーションがこちらです。
※全部やると163MBとなり、Qiitaにアップロードできなかったので、下ではShort版を見せています。
save()
の引数を簡単に説明しておくと、
-
save_all
:True
にしておかないとアニメーションにならない -
duration
:1フレームあたりの表示時間(単位:ミリ秒) -
loop
:0
にすると無限ループ、1
以上にするとその指定回数で再生停止 -
optimize
:True
にするとGIF画像の最適化2が行われる
ソースコード
今回使ったコードなどはGitHubに上げています。
本記事のは02-weathermap
に入っています。