SVG
d3.js

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

More than 3 years have passed since last update.

都道府県別のアクセス数みたいなものを、種類別に地図上で塗り分ける、というのを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を使えばそんなに難しくないな、と思いました。