huruyosi’s blog

プログラミングとかインフラとかのメモです。

チュートリアル 「D3.jsとTopoJSONで地図を作る」を元に日本地図を作ってみる。

やりたいこと

前回は http://ja.d3js.node.ws/blocks/mike/map/ をに従ってイギリスの地図を作成しました。イギリスでは、いまいち実感がなく、チュートリアルの序盤で行うデータ作成がイギリスを対象にしていたからです。それならば日本を対象にしてデータを作成して、日本地図を作って見ます。

huruyosi.hatenablog.com

小笠原諸島が「Bonin island」であり、南方諸島が「Volcano island」 なので外国の人が作ったことを窺わせる名称になっています。

できあがったもの

f:id:huruyosi:20160206132140p:plain

日本の行政区には関係がなく、島を単位にしたデータのようです。d3.jsで日本地図を作る方法を調べると 国土数値情報 行政区域データの詳細 のデータを使う理由を納得できました。

実際のページ http://huruyosiathatena.github.io/d3js_map01/map_mercator_jp.html

ソースコード https://github.com/huruyosiathatena/d3js_map01/tree/master

チュートリアルからの変更

データ作成

下の方法でtopojsonを作ります。

$ ogr2ogr    -f GeoJSON    -where "adm0_a3 = 'JPN'" subunits_jp.json ne_10m_admin_0_map_subunits.shp
$ ogr2ogr    -f GeoJSON    -where "iso_a2 = 'JP' " places_jp.json ne_10m_populated_places.shp
$ topojson    --id-property SU_A3    -p NAME=name    -p NAME    -o jp.json subunits_jp.json places_jp.json

地図の投影方法と中心位置を変更

メルカトル法にして、中心位置を東経135度、北緯35度にしました。

var projection = d3.geo.mercator()
   .center([135, 35])
   .scale(2400)
   .translate([width / 2, height / 2]);

色付け

d3.jsが提供する d3.scale.category20() を使うことにしました。

オブジェクト名変更

理由が分からないのですが、topojsonのobjectsの下にあり、形状のsubunitsと地名のplacesのオブジェクト名に「_jp」がついていました。

全体のソース

<!DOCTYPE html>
<meta charset="utf-8">
<style>

.subunit-boundary {
  fill: none;
  stroke: #777;
  stroke-dasharray: 2,2;
  stroke-linejoin: round;
}


.place,
.place-label {
   fill: #444;
}

text {
   font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
   font-size: 10px;
   pointer-events: none;
}

.subunit-label {
  fill: #777;
  fill-opacity: .5;
  font-size: 20px;
  font-weight: 300;
  text-anchor: middle;
}


</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="http://d3js.org/topojson.v0.min.js"></script>
<script>

var width = 960,
    height = 1160;

var color = d3.scale.category20();

var projection = d3.geo.mercator()
   .center([135, 35])
   .scale(2400)
   .translate([width / 2, height / 2]);

var path = d3.geo.path().projection(projection);

var svg = d3.select("body").append("svg")
    .attr("width", width)
    .attr("height", height);

d3.json("jp.json", function(error, jp) {

    console.log(jp);
     // 国を表示
     svg.selectAll(".subunit")
        .data(topojson.object(jp, jp.objects.subunits_jp).geometries)
    .enter()
    .append("path")
    .attr("class", function(d){ console.log(d.id);return "subunit "+ d.id; } )
    .attr("d", path)
    .attr("fill", function(d,i){ return color(i);});

    // 都市名の○を表示
    svg.append("path")
        .datum(topojson.object(jp, jp.objects.places_jp))
        .attr("d", path)
        .attr("class", "place");

    // 都市名を表示
    svg.selectAll(".place-label")
        .data(topojson.object(jp, jp.objects.places_jp).geometries)
      .enter().append("text")
        .attr("class", "place-label")
        .attr("transform", function(d) { return "translate(" + projection(d.coordinates) + ")"; })
        .attr("dy", ".35em")
        .text(function(d) { return d.properties.NAME; });

    // 都市名を左側と右側で外に向かうようにする
    svg.selectAll(".place-label")
        .attr("x", function(d) { return d.coordinates[0] > 135 ? 6 : -6; })
        .style("text-anchor", function(d) { return d.coordinates[0] > 135 ? "start" : "end"; });

    // ラベル表示
    svg.selectAll(".subunit-label")
        .data(topojson.object(jp, jp.objects.subunits_jp).geometries)
      .enter().append("text")
        .attr("class", function(d) { return "subunit-label " + d.id; })
        .attr("transform", function(d) { return "translate(" + path.centroid(d) + ")"; })
        .attr("dy", ".35em")
        .text(function(d) { return d.properties.NAME; });
});


</script>