🌞

Mapbox Newsletter WEEKLY TIPSの解説 -「ヒートマップレイヤーの作成」

2023/07/20に公開

はじめに

この記事は、先日配信されたMapbox NewsletterのWEEKLY TIPSで紹介されていた「ヒートマップレイヤーの作成」についての解説です。このサンプルではヒートマップレイヤーを作成する方法を例示しています。

ヒートマップの作成方法についてはMapbox Newsletterでも紹介されていた【チュートリアル】Mapbox Studioで隕石落下地点のヒートマップを作成してみる|地図デザインの基礎も合わせてご参照いただければと思います。

また、Newsletterの購読はこちらからお申し込みいただけます。

コードを確認

まずExamplesのコードを見に行きましょう。

日本語サイト

英語サイト

基本的に同じコードですが、英語版はスタイルがMapbox Dark v11にアップグレードされているのでこちらを使用します。Mapbox Dark v10ではデフォルトのプロジェクションがWebメルカトルであるのに対し、Mapbox Dark v11ではGlobe(3D表示された地球)なので、印象がかなり異なります。

今回もコードが少し長めでドキッとしますが、順番に見ていけば大丈夫です。

HTML/CSS

まずHTMLを見ていきましょう。

以下は地図を表示するエレメントです。

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

Mapの作成

次にJavaScriptのコードを見ていきます。以下のコードはいつも通り、Mapオブジェクトを作成しています。containerで地図を表示するHTMLエレメントのidを指定します。

const map = new mapboxgl.Map({
  container: 'map',
  // Choose from Mapbox's core styles, or make your own style with Mapbox Studio
  style: 'mapbox://styles/mapbox/dark-v11',
  center: [-120, 50],
  zoom: 2
});

loadイベント(map.on('load', () => {})の中身)で1つのソース、2つのレイヤーを追加しています。

ソース

まず、ソースを見てみます。

dataURLが指定されており、そこからGeoJSONを入手しています。

map.addSource('earthquakes', {
  'type': 'geojson',
  'data': 'https://docs.mapbox.com/mapbox-gl-js/assets/earthquakes.geojson'
});

データの中身を覗いてみると以下のようなFeatureが大量に並んでいます。Pointデータで、プロパティとしてmag(マグニチュード)などが含まれていることからもわかるように、これは地震のデータです。

{
  "type": "Feature",
  "properties": {
    "id": "ak16994521",
    "mag": 2.3,
    "time": 1507425650893,
    "felt": null,
    "tsunami": 0
  },
  "geometry": {
    "type": "Point",
    "coordinates": [
      -151.5129,
      63.1016,
      0
    ]
  }
}

ヒートマップレイヤー

次に1つ目のレイヤー、ヒートマップレイヤーを見てみます。まずヒートマップレイヤーで大事なことは以下の3点です。

  • ヒートマップは何らかの密度の分布を色で表現
  • 密度の値が0~1の間で変化
  • 0~1の値に応じた色を設定しておくことで分布の色味を決定

ヒートマップレイヤーを作成するためにはtypeheatmapを指定します。また、maxzoom9としていることから、ズームレベルが9以上になるとここで作成したヒートマップレイヤーは表示されなくなります。さらに、addLayerの第二引数に'waterway-label'が指定されているので、waterway-labelレイヤーの下に配置されます。

map.addLayer(
{
  'id': 'earthquakes-heat',
  'type': 'heatmap',
  'source': 'earthquakes',
  'maxzoom': 9,
  'paint': {
    ...
  },
  'waterway-label'
}

paintの中身を見ていきます。

heatmap-weightは重み値です。密度を表す0~1の値に使用される基準値となります。ここではソースのプロパティのmagを読み取り、マグニチュードが0のときは0、6のときは1を出力します。それ以外の値は線形補間(interpolate['linear'])されます。

'heatmap-weight': [
  'interpolate',
  ['linear'],
  ['get', 'mag'],
  0,
  0,
  6,
  1
],

heatmap-intensityは強度値です。ズームレベルに応じてweightに乗じる値を指定します。ヒートマップは密度を表現しますが、ズームすればするほどデータがスカスカになって密度が下がるので、ズームレベルに応じてintensityを乗算することで値が0に張り付くのを防ぎます。ここではzoomが0のとき1、9のとき3を乗算します。

'heatmap-intensity': [
  'interpolate',
  ['linear'],
  ['zoom'],
  0,
  1,
  9,
  3
],

heatmap-colorは色設定です。0~1と変化する値に応じて出力する色を設定しています。

'heatmap-color': [
  'interpolate',
  ['linear'],
  ['heatmap-density'],
  0,
  'rgba(33,102,172,0)',
  0.2,
  'rgb(103,169,207)',
  0.4,
  'rgb(209,229,240)',
  0.6,
  'rgb(253,219,199)',
  0.8,
  'rgb(239,138,98)',
  1,
  'rgb(178,24,43)'
],

heatmap-radiusは帯域幅(Bandwidth)の設定です。Mapbox GL JSのヒートマップではカーネル密度推定と呼ばれる方法で密度を推定していますが、帯域幅はそこで用いられる値です。radiusという名前がついている通り、データのある点からどのぐらいの距離までを影響範囲とするかを指定します。ズームすればするほどデータがスカスカになって密度が下がるので、ズームレベルに応じてradiusを大きくすることで値が0に張り付くことを防止しています。

'heatmap-radius': [
  'interpolate',
  ['linear'],
  ['zoom'],
  0,
  2,
  9,
  20
],

最後がheatmap-opacityで不透明度です。ズーム7から9で不透明度が1から0に変化します。この設定により、サークルレイヤーになめらかに視覚効果が移行するようにしています。

'heatmap-opacity': [
  'interpolate',
  ['linear'],
  ['zoom'],
  7,
  1,
  9,
  0
]

以上がヒートマップレイヤーの使い方となります。リファレンスも合わせてご参照ください。

サークルレイヤー

ヒートマップレイヤーはデータの存在するポイントを中心に、ぼやっとした分布を色で表現していました。サークルレイヤーはそれに加えてそのポイントの位置を表示するために使用されます。つまり、ヒートマップレイヤーの使い方としては必ずしも必要なレイヤーではないです。

minzoom7が指定されているので、ズームレベルが7未満では表示されません。ヒートマップで不透明度がズームレベル7以上で変化していましたが、ちょうどそのズームレベルからサークルを表示させるようにしています。また、addLayerの第二引数に'waterway-label'が指定されているので、このレイヤーの下に配置されます。

map.addLayer(
{
  'id': 'earthquakes-point',
  'type': 'circle',
  'source': 'earthquakes',
  'minzoom': 7,
  'paint': {
    ...
  },
  'waterway-label'
);

paintの中身を見ていきます。

circle-radiusは円の半径です。magの値に応じて大きく、ズームレベルに応じて大きな円になるように設定されています。

'circle-radius': [
  'interpolate',
  ['linear'],
  ['zoom'],
  7,
  ['interpolate', ['linear'], ['get', 'mag'], 1, 1, 6, 4],
  16,
  ['interpolate', ['linear'], ['get', 'mag'], 1, 5, 6, 50]
],

circle-colorは円の色です。これもmagの値に応じて色を変えています。

'circle-color': [
  'interpolate',
  ['linear'],
  ['get', 'mag'],
  1,
  'rgba(33,102,172,0)',
  2,
  'rgb(103,169,207)',
  3,
  'rgb(209,229,240)',
  4,
  'rgb(253,219,199)',
  5,
  'rgb(239,138,98)',
  6,
  'rgb(178,24,43)'
],

circle-strokeは円の縁の設定です。縁の色が白で、ズームレベルに応じて太くしています。

'circle-stroke-color': 'white',
'circle-stroke-width': 1,
  // Transition from heatmap to circle layer by zoom level
  'circle-opacity': [
  'interpolate',
  ['linear'],
  ['zoom'],
  7,
  0,
  8,
  1
]

まとめ

ヒートマップレイヤーの使い方について確認しました。設定項目は多いですが、サンプルやチュートリアルを動かして雰囲気を掴んでみてください。

GitHubで編集を提案
マップボックス・ジャパン合同会社

Discussion