Leaflet Tutorials Interactive Choropleth Map をやりたかったので下訳した

この記事は Leaflet Interactive Choropleth Map を自分で試した際のメモです。 訳の正確性はないと思います。

インタラクティブ統計区域別表現地図

このチュートリアルではアメリカ合衆国の人口密度使ってカラフルなインタラクティブ統計区域別表現地図を作ります。 Using GeoJSON with LeafletCustom Controls も参考にしてください。

このチュートリアルTexas Tribune US Senate Runoff Results map (also powered by Leaflet) に触発されて Ryan Murphy によって作成されました。

  • map省略

サンプルページを見る

データソース

アメリカの州ごとの人口密度を可視化します。データ量(州の形状と各州の密度)はそれほど大きくないため、最も便利で簡単なのはGeoJSONに格納して表示する方法です。

ここで使用するGeoJSONデータ us-states.js は次のような形になっています。

{
    "type": "Feature",
    "properties": {
        "name": "Alabama",
        "density": 94.65
    },
    "geometry": ...
    ...
}

州の形状はアメリカ国勢調査局にある2011年7月1日のデータに基づいており、D3js で有名な Mike Bostock によって Wikipedia の記事 から人口密度の値を負荷されて公開されました。

背景地図

統計区域別表現地図が視覚化の背景地図として完璧に仕上げるために、素敵なグレースケール用カスタム Mapbox スタイルの地図を表示してみましょう:

var map = L.map('map').setView([37.8, -96], 4);

L.tileLayer('http://{s}.tiles.mapbox.com/{id}/{z}/{x}/{y}.png', {
    id: 'examples.map-20v6611k',
    attribution: ...
}).addTo(map);

L.geoJson(statesData).addTo(map);
  • map省略

色の追加

州の人口密度に応じて着色を変更する必要があります。地図に応じた色を選ぶのは難しいことですが、それを支援するための ColorBrewer という素晴らしいツールがあります。それを使って得た色の値を、人口密度に応じて色を返す関数の値として組み込んで作成します:

function getColor(d) {
    return d > 1000 ? '#800026' :
           d > 500  ? '#BD0026' :
           d > 200  ? '#E31A1C' :
           d > 100  ? '#FC4E2A' :
           d > 50   ? '#FD8D3C' :
           d > 20   ? '#FEB24C' :
           d > 10   ? '#FED976' :
                      '#FFEDA0';
}

次に GeoJSON レイヤーにスタイル関数を定義して、人口密度の値によって塗りつぶしの色や外観を少し調整し、縁を破線にします。

function style(feature) {
    return {
        fillColor: getColor(feature.properties.density),
        weight: 2,
        opacity: 1,
        color: 'white',
        dashArray: '3',
        fillOpacity: 0.7
    };
}

L.geoJson(statesData, {style: style}).addTo(map);

この方がはるかに良いですね!

  • map省略

視覚効果の追加

マウスでホバーしたときに視覚的に強調表示できるよう、レイヤーに mouseover イベントを定義します:

function highlightFeature(e) {
    var layer = e.target;

    layer.setStyle({
        weight: 5,
        color: '#666',
        dashArray: '',
        fillOpacity: 0.7
    });

    if (!L.Browser.ie && !L.Browser.opera) {
        layer.bringToFront();
    }
}

ここでは、e.target を通してマウスがホバーされた州を前面に表示し、ハイライト効果として境界線を太い灰色に設定します(ただし、IEOpera ではマウスオーバーによる bringToFront コントロールに問題を抱えているため bringToFront をさせません)。

次に、mouseout イベントを定義します:

function resetHighlight(e) {
    geojson.resetStyle(e.target);
}

geojson.resetStyle (Leaflet で定義されている)は、レイヤースタイルをデフォルトの状態に戻す便利なメソッドです。このメソッドが機能するためには GeoJSON レイヤーが geojson 変数を介してアクセス可能になっている必要があるため、 geojson 変数よりも先に関数を定義して後からレイヤーに割り当てる必要があります:

var geojson;
// ... our listeners
geojson = L.geoJson(...);

次のように、クリックされたポリゴンにズームする関数を定義することもできます:

function zoomToFeature(e) {
    map.fitBounds(e.target.getBounds());
}

州のレイヤー上に関数を追加するため onEachFeature オプションを利用します:

function onEachFeature(feature, layer) {
    layer.on({
        mouseover: highlightFeature,
        mouseout: resetHighlight,
        click: zoomToFeature
    });
}

geojson = L.geoJson(statesData, {
    style: style,
    onEachFeature: onEachFeature
}).addTo(map);

これの関数はマウスホバーされた州がハイライト表示になる機能を提供します。

カスタムインフォメーションコントロール

州ごとに異なる情報を表示するためにポップアップを使用することもできますが、今回は別の方法を使います -- 州がホバーされると custom control で表示します。

custom control に使うコードはは次の通りです:

var info = L.control();

info.onAdd = function (map) {
    this._div = L.DomUtil.create('div', 'info'); // create a div with a class "info"
    this.update();
    return this._div;
};

// method that we will use to update the control based on feature properties passed
info.update = function (props) {
    this._div.innerHTML = '<h4>US Population Density</h4>' +  (props ?
        '<b>' + props.name + '</b><br />' + props.density + ' people / mi<sup>2</sup>'
        : 'Hover over a state');
};

info.addTo(map);

ユーザーが州にマウスホバーさせた時に custom control を更新する必要があるので、次のように関数を変更します:

function highlightFeature(e) {
    ...
    info.update(layer.feature.properties);
}

function resetHighlight(e) {
    ...
    info.update();
}

custom control の見栄えを良くするために CSS スタイルを定義します:

.info {
    padding: 6px 8px;
    font: 14px/16px Arial, Helvetica, sans-serif;
    background: white;
    background: rgba(255,255,255,0.8);
    box-shadow: 0 0 15px rgba(0,0,0,0.2);
    border-radius: 5px;
}
.info h4 {
    margin: 0 0 5px;
    color: #777;
}

カスタム凡例

凡例は静的で、州のマウスホバーで変化しないため、custom contorol を作成することは簡単です。JavaScript コード:

var legend = L.control({position: 'bottomright'});

legend.onAdd = function (map) {

    var div = L.DomUtil.create('div', 'info legend'),
        grades = [0, 10, 20, 50, 100, 200, 500, 1000],
        labels = [];

    // loop through our density intervals and generate a label with a colored square for each interval
    for (var i = 0; i < grades.length; i++) {
        div.innerHTML +=
            '<i style="background:' + getColor(grades[i] + 1) + '"></i> ' +
            grades[i] + (grades[i + 1] ? '&ndash;' + grades[i + 1] + '<br>' : '+');
    }

    return div;
};

legend.addTo(map);

custom control のための CSS スタイル(先に定義されたスタイルを再利用):

.legend {
    line-height: 18px;
    color: #555;
}
.legend i {
    width: 18px;
    height: 18px;
    float: left;
    margin-right: 8px;
    opacity: 0.7;
}

Interactive Choropleth Mapのトップまたはサンプルページをお楽しみください。

訳は以上です

訳を作りながら書いていたらなんとか適当なデータで同じ様な表示をすることができたので次のステップに進みたいと思います。