D3.jsで日本地図を描き、都道府県別に色を塗る

  • 54
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

都道府県別のアクセス数みたいなものを、種類別に地図上で塗り分ける、というのをD3.jsでやってみようと思います。

ちなみにD3.jsはぜんぜん知らなかったので、とりあえず基本のチュートリアル地図のチュートリアルを読みました。

ツールのインストール

地図データの変換とかをするためのツールをインストールします。(Macです。)

$ brew install gdal
$ brew install node
$ npm install -g topojson

地図データのダウンロードと変換

Natural Earthから都道府県レベルの地図データをダウンロードします。

http://www.naturalearthdata.com/http//www.naturalearthdata.com/download/10m/cultural/ne_10m_admin_1_states_provinces.zip

解凍するとファイルが色々ありますが、ne_10m_admin_1_states_provinces.shp というファイルを指定して日本のデータのGeoJSONファイルを作ります。

$ ogr2ogr -f GeoJSON -where "adm0_a3 = 'JPN'" pref.json ne_10m_admin_1_states_provinces.shp

pref.jsonというファイルができました。
このファイルからTopoJSONファイルを作るのですが、なぜか静岡県の名前がnullになっているので、pref.jsonファイルを開いて、"name":"Shizuoka"になっている行の"name_local":null"name_local":"静岡県"に修正しておきます。
(ちなみに1個目の"name":nullになってる行もよくわからないけど消して良さそう。)

TopoJSONファイルを作ります。

$ topojson -p name -p name_local -p latitude -p longitude -o japan.json pref.json

japan.jsonというファイルができました。

表示データの準備

表示したい都道府県別のデータは、ID => 都道府県名の配列と、ID => アクセス数の配列の2つがPHPであるので、それぞれ使いやすい形にしてJSONにしておきます。

<?php
$pref = array(1 => '北海道', 2 => '青森県', ... , 47 => '沖縄県');
$category = array(
        array(
                'name' => 'カテゴリー1',
                'data' => array(1 => 291, 2 => 19, ... , 47 => 3)
        ),
        ...
        array(
                'name' => 'カテゴリー2',
                'data' => array(1 => 111, 2 => 39, ... , 47 => 24)
        ),
);
?>
<script type="text/javascript">
var pref = <?php echo json_encode(array_flip($pref), JSON_UNESCAPED_UNICODE); ?>;
var category = <?php echo json_encode($category, JSON_UNESCAPED_UNICODE); ?>;

それぞれ、

var pref = {"北海道":1,"青森県":2, ... ,"沖縄県":47};
var category = [{"name":"カテゴリー1","data":{"1":291,"2":19, ... , "47":3}},{"name":"カテゴリー2","data":{"1":111,"2":39, ... , "47":24}}];

のようになります。
地図データに漢字の都道府県名が入っているので、そこからIDを引けるようにしておきます。

D3.js

まず地図を表示。

var width = 900,
    height = 960;

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

var projection = d3.geo.mercator()
    .center([136, 35.5])
    .scale(2000)
    .translate([width / 2, height / 2]);

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

d3.json("japan.json", function(error, japan) {
    var topo = topojson.object(japan, japan.objects.pref).geometries;
    svg.selectAll(".pref")
        .data(topo)
        .enter()
        .append("path")
        .attr("class", function(d) {
            return "pref pref" + pref[d.properties.name_local];
        })
        .attr("d", path);
});

各都道府県のパスにprefというクラスと、都道府県別のIDが付いたクラス(北海道ならpref1沖縄ならpref47)を付けておきます。
cssで白地図にします。

<style type="text/css">
.pref {
    fill: #fff;
    stroke: #aaa;
}
</style>

地図の横にカテゴリー名を表示して、そのテキストをマウスオーバーした時に、該当するカテゴリーの数値情報が地図上の色でわかるようにします。
数値が多い都道府県がより濃い赤になるようにしました。(255以上の値はみんな同じ色になりますが。)

svg.selectAll("text")
    .data(category)
    .enter()
    .append("text")
    .attr("class", "category-label")
    .attr("x", width - 160)
    .attr("y", function(d, i) {
        return i * 20 + 220;
    })
    .text(function(d) {
        return d.name;
    })
    .on("mouseover", function(d) {
        for (var key in d.data) {
            var color = 255 - d.data[key];
            if (color < 0) {
                color = 0;
            }
            d3.select(".pref" + key)
                .transition()
                .style("fill", "rgb(255, " + color + ", " + color + ")");
        }
        d3.select(this).style("fill", "#f66");
    })
    .on("mouseout", function(d) {
        for (var i = 1; i < 48; i++) {
            d3.select(".pref" + i)
                .transition()
                .style("fill", "#fff");
        }
        d3.select(this).style("fill", "black");
    });

『カテゴリー2』のテキストの上にマウスを置くと、このようになります。
スクリーンショット 2016-01-14 11.03.10.png

地図描くのもD3.jsを使えばそんなに難しくないな、と思いました。