Help us understand the problem. What is going on with this article?

風速データをパーティクルで描画する

leaflet.jsのプラグイン『leaflet-velocity』は、物凄く簡単に風をパーティクルで描画できます。
leaflet-velocity

この記事では、leafet-velocityを使って、気象庁の風速データを視覚化したいと思います。
ほとんどGitHubに書いてあるようなことなので、あくまでプログラミング初心者の方向けです。

1. 風速データを取得する。

データは、京都大学のデータサーバに置いてあるので、それを取ってきます。
1. 地球流体電脳倶楽部
2. データサーバ
3. 気象庁データ
4. 数値予報GPV
5. 任意の日時を選択

今回は2018年5月15日の午前0時(日本時間9時)の、地上10m地点の風速データを使います。 ですので、ダウンロードするファイルはこちらになります。

window date


Z_C_RJTD_20180515000000_MSM_GPV_RjpLsurf_FH00-15_grib2.bin

MSM, GPV, Lsurf 等の意味についてはここでは触れません。(私もあまり自信がないので)。

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

大体、気象データは "grib" という形式で記述されています。
このファイルを人間が解読するには、wgrib2というツールを使うのが便利です。
(wgrib2の導入は別の記事にも書いていますのでご参照ください。) では、さっそくwgrib2を使っていきます。


まずは風速データのみを一覧表示してみます。
gribファイルは通常、一つのファイルに色々な種類のデータが入っています。

$ wgrib2 (gribファイル)

このコマンドでもデータの一覧表示ができますが、量が多すぎて大変なので、-matchオプションを使って風速データのみを取り出します。
(ちなみに、風速はU:東西方向、V:南北方向 の二つから成り立っています。なので、風速を扱いたいときは、UGRD, VGRD両方を取り出す必要があります。)

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

wgrib2

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

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

このような出力の場合、
- 1.3 => データのインデックス番号
- d=2018051500 => 2018年5月15日のデータ
- UGRD => U方向の強さ
- 10m above ground => 地上10m地点
- anl => 何時間後の数値予想か(anlの場合は0)

となります。
今回は要件が【地上10m地点で午前0時時点の風速データ】なので、一番上(index番号が1.3のデータ)で良さそうです。


次は、U, V それぞれの方向のデータを取り出します。
wgrib2 の-dオプションに、取り出したいデータのインデックス番号を与えることで、データを抽出できます。

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

wgrib

出力ファイルは、U方向のデータということで、"u.grib2" という名前にしました。
そのあと、同じようにして"v.grib2"ファイルも準備します。
![キャプチャ.PNG](https://qiita-image-store.s3.amazonaws.com/0/165044/c8087230-5ab8-09bd-f7eb-f0ee179718d6.png)


次にU, V それぞれのファイルを連結する。
これは、leaflet-velocityが読み込む際に必要な手順となります。
ここはさらっと流します。

$ copy /b u.grib2 + v.grib2 wind.grib2

==出力==
u.grib2
v.grib2
1 個のファイルをコピーしました。


最後に、gribファイルをJSON形式に変換します。
leaflet-velocityで風速データを読み込ませるには、形式をJSONにする必要があります。
そこで、grib2json というツールを使います。

実際に変換するコマンドはこちらです。

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

HTML, JavaScriptを準備

以下のコードでは、leafletはCDNを使用します。 leaflet-velocityは予め用意しておいてください。 Leaflet-Velocity

index.html
<body>
  <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">&lt;/script>
  <link rel="stylesheet" href="leaflet-velocity.css" />
  <script src="leaflet-velocity.js">&lt;/script>

  <div id="map">&lt;/div>

  <link rel="stylesheet" href="style.css" />
  <script src="script.js">&lt;/script>

</body>

css:style.css

style.css
#map {
  width: 100vw;
  height: 100vh;
}

js:script.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 baseLayers = {
        "Satellite": Esri_WorldImagery,
        "OpenElevationMap": Stamen_TerrainBackground,
        "CartoDB.DarkMatter": CartoDB_DarkMatterNoLabels
    };

    // マップ設定
    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;

// load data (u, v grids) from somewhere (e.g. https://github.com/danwild/wind-js-server)
$.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 - Great Barrier Reef');
});

これだけでOKで。
地図の日本周辺に小さい点で風が描画されるはずです。
データの準備さえできてしまえば、かなり簡単にお洒落なパーティクル処理が実装できますね。

mi-miya
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした