LoginSignup
89
80

More than 5 years have passed since last update.

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

Posted at

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

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

ツールのインストール

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

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

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

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

解凍するとファイルが色々ありますが、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を使えばそんなに難しくないな、と思いました。

89
80
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
89
80