読者です 読者をやめる 読者になる 読者になる

データ分析エンジニアが気まぐれに更新するブログ

勉強してきた技術などを適当に書いていければと思います。

Leaflef.jsとD3.jsでマップデータを可視化してみた

JavaScript D3.js データ可視化 Leaflet.js

Leaflet.js

Leaflet.jsというWebマップ表示ライブラリを知りましたので、使ってみました。


Leaflet.js : http://leafletjs.com/


結構前からあったそうな。


※画像をクリックするとページを移動します。


OpenStreetMapは知っていたけども、敷居が高そうと思っていましたが、たったこれだけのソースで表示できてしまった...。

function _map(){
  this.targetDivId = "map";
  this.leafletMap;
  this.viewLocation = {"lon": 139.691706, "lat": 35.689488}; 
  this.mapLink = '<a href="http://openstreetmap.org">OpenStreetMap</a>';
}
// _map draw
_map.prototype.draw = function(){
  this.leafletMap = L.map(this.targetDivId).setView([this.viewLocation.lat, this.viewLocation.lon], 4);
  L.tileLayer(
    "http://{s}.www.toolserver.org/tiles/bw-mapnik/{z}/{x}/{y}.png", {
      attribution: "&copy; " + this.mapLink + " Contributors",
      maxZoom: 18,
    }
  ).addTo(this.leafletMap);
  this.leafletMap._initPathRoot();
}

// init
function init(){
  var map = new _map();
  map.draw();
}


カスタマイズ性が低いとのことだけども、地図自体はカスタマイズする機会も少ないだろうし、基本的な可視化機能として、マーカーを置いたり、地形に色を塗ったりできるようです。

使いこなしていけば、いろんなことが出来るかもしれません。


D3.jsとの連携

ちなみにD3.jsとの連携も出来るようです。

実際に簡単にやってみたところ、このような感じになりました。


※画像をクリックするとページを移動します。

var map, svg, g;
function init(){
  map = L.map("map").setView([39.702053, 141.15448379999998], 6);
  L.tileLayer(
    "http://{s}.www.toolserver.org/tiles/bw-mapnik/{z}/{x}/{y}.png", {
    attribution: '&copy; <a href="http://openstreetmap.org">OpenStreetMap</a> Contributiors',
    maxZoom: 18,
  }).addTo(map);
  map._initPathRoot();
  svg = d3.select("#map").select("svg");
  g = svg.append("g");
  d3.json("data/japan.geojson", function(json){
    drawpolygon(json);
    d3.json("data/points.geojson", function(json){
      drawpoint(json);
    });
  });
}
function drawpolygon(json){
  var geojson = json.type == "Topology" ? topojson.feature(json, json.objects.ken) : json;
  var transform = d3.geo.transform({point: projectPoint});
  var path = d3.geo.path().projection(transform);
  featureElement = g.selectAll("path")
    .data(geojson.features)
    .enter()
    .append("path")
    .attr({
      "stroke": "#00AA11",
      "fill": "#AAFFAA",
      "fill-opacity": 0.4,
    });
  map.on("viewreset", update);
  update();
  function update (){
    featureElement.attr("d", path);
  }
  function projectPoint(x, y){
    var point = map.latLngToLayerPoint(new L.LatLng(y, x));
    this.stream.point(point.x, point.y);
  }
}
function drawpoint(json){
  json.features.forEach(function(d){
    d.LatLngObj = new L.LatLng(d.geometry.coordinates[1], d.geometry.coordinates[0]);
  });
  var circle = g.selectAll("circle")
    .data(json.features)
    .enter()
    .append("circle")
    .attr({
      "stroke": "black",
      "stroke-width": 1,
      "opacity": 0.7,
      "fill": "red",
      "r": 10,
    });
  map.on("viewreset", update);
  update();
  function update(){
    circle.attr("transform", function(d){
      return "translate(" + map.latLngToLayerPoint(d.LatLngObj).x + "," + map.latLngToLayerPoint(d.LatLngObj).y + ")";
    });
  }
}


いやいや十分でしょ!

あとは、D3.jsのスケール関数とかで色の濃淡や、ポイント円の大きさでデータを表示もできますし、ポイント間に線を引っ張ることもできますし。

2D地図のオーバーレイ可視化で良いのならば、かなり多彩な表現が可能なのでは...。

D3.jsでgeojsonやtopojsonを読み込んで地形を表示して頑張る必要はなかったらしい笑

まあ、デザイン性を追求するならば、自前で頑張るのも良いかもしれませんが、しかし、拡大・縮小で自動的に地名や境界線などの粒度も調整してくれる地図クライアントツールってところは大きいですねー。

うーん、これで色々格好良くて、便利に可視化してみたいです。