近畿地方で春一番が吹いたので可視化してみた(風の描画/データ準備編)

7 min read読了の目安(約6600字

こんにちは、三知制作 宮原です。

本日(記事執筆時 3月3日)は朝からめちゃくちゃ寒いです。
昨日は凄く暖かかったのに...

昨日はどうやら近畿地方で『春一番』が吹いたようです。
調べてみたところ、春一番が吹いた日は暖かく、そのあとは寒い日が戻ってくる、ようですね。
そんな春一番、せっかくなので可視化してみよう!ということで、色々と技術を使ってみました。

とりあえず、こんな感じになりました

URLも貼っておきます↓
春一番!

右上のアイコンから 『Wind - Japan 2021.3.2 -』をチェックしてもらうと、キレイに風が描画されます。

分かる人ならすぐにお分かりかと思いますが、こちらはマップを表示するJSプラグイン『Leaflet』と、気象関係のベクトルデータを表示するための『Leaflet Velocity』をゴリゴリに使って、サクッと制作しています。

昨日はとても風の強い日だったようです。
実際、春一番の条件として

  • 立春から春分の期間
  • 日本海に低気圧がある
  • 最大風速8メートル以上
  • 南よりの風
    とあるので、強い風も必須条件のようですね。

春一番って、てっきり特定の風に対して命名されるのかと思っていたのですが、そうではなく 上記条件を満たした日が春一番の日 なのですね。
賢くなった!

なので、3月2日のデータを描画したらそれはもう春一番を描画したと言ってもいいですよね?

使用した技術

改めて仕様技術についてご説明します。

Leaflet

Leaflet

an open-source JavaScript library
for mobile-friendly interactive maps

だそうです。

HTMlに地図を組み込む場合、(google map埋め込みなどを除き)一番先に選択肢に上がるほど有名なライブラリですね。

今回は、Open Street Map と合わせて使用してみました。

Leaflet Velocity

Leaflet Velocity

A plugin for Leaflet (v1.0.3, and v0.7.7) to create a canvas visualisation layer for direction and intensity of arbitrary velocities (e.g. wind, ocean current).

だそうです。

風・海流等の気象関連のベクトルデータを、きれいなパーティクルで表示してくれます。
気象データをJSON形式にしないといけなかったり、多少読み込みに時間がかかったりしますが、何よりも美しく描画してくれるので大好きです。

風データ

風のデータは、北海道大学・京都大学・九州大学が共同で管理しているサイト『地球流体電脳倶楽部』からいただきました。
地球流体電脳俱楽部

何とも怪しい名前のサイトですが、安全です。

今回は、3月2日の地上10m付近で観測された風のデータを使用しますので、

  1. データサーバ
  2. 気象庁データ
  3. 数値予報GPV
  4. 数値予報GPV(2回目)

とリンクを進んでいき、3月2日のデータを取得します。

データを落とす

上記手順でリンクを進み任意の日付を選択すると、下記のように画像が一覧表示されるかと思います。

その中から、今回は Z__C_RJTD_20210302000000_GSM_GPV_Rjp_Lsurf_FD0000-0312_grib2.bin というデータを使用していきます。

なんだかよく分からない英語が並んでいますが、一つずつの意味は多分下記のような感じ。

  • Z__C_RJTD : 意味不明。データを区分するためのタグで深い意味はないのかも?
  • 20210302000000 : 2021年3月2日0時のデータ
  • MSM : メソ数値予報モデルGPVのこと。日本を5㎞間隔の格子で分割し、各点(格子点)のデータを扱うということ
  • GPV : 格子点値のこと。格子点上の気象情報等を表すデータのこと
  • Rjp : 日本のデータですよ、ということ。多分
  • Lsurf : 地上面のデータであることを示している。海面気圧・地上気圧・気温・風・雲量など。
  • FH00-15 : 予報期間のことらしい、詳しくは分からない

今回は風データを可視化する必要があるため、Lsurfと記述されているデータを使う必要があります。
使うファイルがきちんと選べたら、クリックしてダウンロードします!

落としてきたファイルから風データを取り出す!

ここからは、2つのソフトウェアを使用していきます。
『wgrib2』と『grib2json』です。

wgrib2は、気象データなどに使われる Grib という形式を扱うために、ほぼ必須と言っていいと思います。

今回風速データを描画するために使う『leaflet velocity』はgribデータを読み込めないため、json形式にするためにgrib2jsonを使用します。

この記事ではインストール手順については省きますね。

さて、上記2つのツールが用意出来たら、まずはwgrib2で落としてきたデータの中身を見てみましょう。

$ wgrib2 (gribファイル ※落としてきたデータは、拡張子が.binになっているかもしれません)

このコマンドでもGribファイルの中身が一覧で表示できますが、量が多すぎて大変なので -matchオプションを使って風速データのみを取り出してみましょう。

今回は風を可視化するため風のU方向のデータ(UGRD)と、V方向のデータ(VGRD)をそれぞれ抽出する必要があります。

$ wgrib2 (gribファイル) -match UGRD

すると目的のデータが抽出できます。

ここで、少し出力内容を見ていきます。

1.3:0:d=2018051500:UGRD:10 m above ground:anl

このような出力の場合であれば、意味は下記のようになります。

  • 1.3 : データのインデックス番号。この番号を呼び出せば、データの中身が抽出できます
  • d = 日付
  • UGRD : U方向のベクトルであることを示しています
  • 10m above ground : 読んで字のごとく、地上10mの風のデータであることを示しています
  • anl : d の日付から何時間後の予報かを示す。anlは0の意味

今回の場合、番号 1.3 のデータを使えば良さそうですね。

では、まずはU方向のデータを取得します。

$ wgrib2 -d 1.3 (grib2ファイル) -grib u.grib2

このようにすれば、U方向のデータのみを抽出したファイルを出力できます。
同じように、V方向のデータも取得し出力しましょう。

$ wgrib2 (gribファイル) -match VGRD
$ wgrib2 -d 1.4 (grib2ファイル) -grib v.grib2

最後の最後に、gribファイルをJSON形式に変換!!!

$ grib2json --names --data --o wind.json wind.grib2

ここまで来たら、あとは作った wind.json をleaflet velocity に渡してやればよいですね。

あとは読み込ませるだけ!

こんな感じ。
殆どはleaflet velocity にあるデモコード通りで良いですね。
demo

<!doctype html>
<html>
<head>
	<title>LeafletVelocity Demo</title>
	<meta charset="utf-8">
</head>
<body>

<div id="map"></div>

<!--vendor-->
<script src="https://code.jquery.com/jquery-2.2.4.min.js"></script>
<link rel="stylesheet" href="https://npmcdn.com/leaflet@1.1.0/dist/leaflet.css" />
<script src="https://npmcdn.com/leaflet@1.1.0/dist/leaflet.js"></script>

<!--leaflet-velocity-->
<link rel="stylesheet" href="../dist/leaflet-velocity.css" />
<script src="../dist/leaflet-velocity.js"></script>

<!--demo-->
<link rel="stylesheet" href="demo.css" />
<script src="demo.js"></script>

</body>
</html>

demo.js

function initDemoMap() {
  // 衛星写真タイルレイヤ
  var Esri_WorldImagery = L.tileLayer('http://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', {
    attribution: 'Tiles &copy Esri &mdash Source: Esri, i-cubed, USDA, USGS, ' +
    'AEX, GeoEye, Getmapping, Aerogrid, IGN, IGP, UPR-EGP, and the GIS User Community'
  })

  // 地形マップ
  var Stamen_TerrainBackground = L.tileLayer(
      'https://stamen-tiles-{s}.a.ssl.fastly.net/terrain-background/{z}/{x}/{y}.png', {
    attribution: 'Map tiles by <a href="http://stamen.com">Stamen Design</a>, <a href="http://creativecommons.org/licenses/by/3.0">CC BY 3.0</a> &mdash Map data &copy <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>',
    }
  )

  // 黒地マップ
  var CartoDB_DarkMatterNoLabels = L.tileLayer(
    'https://cartodb-basemaps-{s}.global.ssl.fastly.net/dark_nolabels/{z}/{x}/{y}.png', {
    attribution: '&copy <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> &copy <a href="http://cartodb.com/attributions">CartoDB</a>',
    subdomains: 'abcd',
    maxZoom: 19
    }
  var Esri_WorldImagery = L.tileLayer(
  );

  var baseLayers = {
    "Satellite": Esri_WorldImagery,
    "OpenElevationMap": Stamen_TerrainBackground,
    "CartoDB.DarkMatter": CartoDB_DarkMatterNoLabels
  };

  var map = L.map("map", {
    layers: [CartoDB_DarkMatterNoLabels],
    minZoom: 4,
    maxZoom: 10
  });

  var layerControl = L.control.layers(baseLayers);
  layerControl.addTo(map);
  map.setView([36.5, 136], 5)

  return {
    map: map,
    layerControl: layerControl
  };
}

// demo map
var mapStuff = initDemoMap()
var map = mapStuff.map
var layerControl = mapStuff.layerControl

$.getJSON('./wind.json', function (data) {
  var velocityLayer = L.velocityLayer({
    displayValues: true,
    displayOptions: {
      velocityType: 'GBR Wind',
      displayPosition: 'bottomleft',
      displayEmptyString: 'No wind data'
    },
    data: data,
    minVelocity: 0,
    maxVelocity: 11,
    velocityScale: 0.015,
  })
  layerControl.addOverlay(velocityLayer, 'Wind - Japan 2021.3.2 -')
})

自作デモ

まとめ

楽しいね!