Chapter7

D3.js in Actionの7章の勉強ノートです。

最初にきちんと保存できるようにHTMLとd3.v3.min.jsをセットします。

これまで、d3.v3.min.jsを以下のようにロードしていましたが、nvd3のinitialize_javascriptでこれが不要になりました。

ただし、kernelはPython2を使用するため、sageは%load_extでロードします。

<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
In [14]:
%load_ext sage
from IPython.core.display import HTML
from string import Template
import json
import nvd3
nvd3.ipynb.initialize_javascript(use_remote=True)
The sage extension is already loaded. To reload it, use:
  %reload_ext sage

地図データをjupyterで表示することがD3を勉強し始めた契機でした。

3章まで基本を勉強したので、ちょっと飛んで7章を試してみます。

In [2]:
%%writefile css/ch7.css
path.countries {
     stroke-width: 1;
     stroke: black;
     opacity: .5;
     fill: red;
}
circle.cities {
     stroke-width: 1;
     stroke: white;
     fill: black;
}
circle.centroid {
     fill: red;
     pointer-events: none;
}
rect.bbox {
     fill: none;
     stroke-dasharray: 5 5;
     stroke: black;
     stroke-width: 2;
     pointer-events: none;
}
path.graticule {
     fill: none;
     stroke-width: 1;
     stroke: black;
}
path.graticule.outline {
     stroke: black;
}
Overwriting css/ch7.css
In [3]:
%%writefile js/ex7-1.js
d3.json("js/world.geojson", createMap);

function createMap(countries) {
    var width = 350;
    var height = 350;
    var aProjection = d3.geo.mercator()
        .scale(80)
        .translate([width / 2, height / 2]);
    var geoPath = d3.geo.path().projection(aProjection);
    d3.select('#ex1').select("svg").selectAll("path").data(countries.features)
        .enter()
        .append("path")
        .attr("d", geoPath)
        .attr("class", "countries")
}
Overwriting js/ex7-1.js
In [4]:
%%HTML
<!-- CSSの読み込み -->
<link type="text/css" rel="stylesheet" href="css/ch7.css" />
<script src="js/ex7-1.js" type="text/javascript"></script>

<div id="ex1">
    <div id="viz">
      <svg style="width:350px;height:350px;border:1px lightgray solid;" />
      </svg>
    </div>
    <div id="controls" />
</div>

jupyterでqueueを使おうとするとエラーになってしまうので、queueを使わないで、citeisを表示してみます。

In [5]:
%%writefile js/ex7-2.js
d3.json("js/world.geojson", createMap);

var width = 350;
var height = 350;
var aProjection = d3.geo.mollweide()
    .scale(120)
    .rotate([-136, 0])
    .center([0, 38])
    .translate([width / 2, height / 2]);

function createMap(countries) {
    var geoPath = d3.geo.path().projection(aProjection);
    var featureSize = d3.extent(countries.features,
                   function(d) {return geoPath.area(d);});        
    var countryColor = d3.scale.quantize()
                    .domain(featureSize).range(colorbrewer.Reds[7]);
    
    d3.select('#ex2').select("svg").selectAll("path").data(countries.features)
        .enter()
        .append("path")
        .attr("d", geoPath)
        .attr("class", "countries")
        .style("fill", function(d) {
                        return countryColor(geoPath.area(d))
        });
}

d3.csv("data/cities.csv",function(error,data) {createCities(data)});

function createCities(cities) {
    d3.select('#ex2').select("svg").selectAll("circle").data(cities)
        .enter()
        .append("circle")
        .attr("class", "cities")
        .attr("r", 3)
        .attr("cx",  function(d) { return aProjection([d.y, d.x])[0]})
        .attr("cy",  function(d) { return aProjection([d.y, d.x])[1]});
    
}
Overwriting js/ex7-2.js
In [6]:
%%HTML
<!-- CSSの読み込み -->
<link type="text/css" rel="stylesheet" href="css/ch7.css" />
<!-- 外部jsファイル -->
<script src="js/d3.geo.projection.min.js" type="text/javascript"></script>
<script src="js/colorbrewer.js" type="text/javascript"></script>
<script src="js/ex7-2.js" type="text/javascript"></script>

<div id="ex2">
    <div id="viz">
      <svg style="width:350px;height:350px;border:1px lightgray solid;" />
      </svg>
    </div>
    <div id="controls" />
</div>

タイルの利用

タイルを使うと、地図の他に衛星写真やタイルに変換された地図情報を地図に重ね合わせて表示することができます。

In [7]:
%%writefile js/ex7-3.js
var width = 500, height = 500;
var takaokaBoundingBox = {geometry: {coordinates: [[[136.904778, 36.822525], [137.072662, 36.822525], [137.072662, 36.658552], [136.904778, 36.658552], [136.904778, 36.822525]]], type: "Polygon"}, id: 999999, properties:{}, type: "Feature"};

d3.select("#ex3").select("svg").append("g").attr("id", "tiles");
d3.select("#ex3").select("svg").append("g").attr("id", "vectors");

var tile = d3.geo.tile()
    .size([width, height]);

var projection = d3.geo.mercator()
    .scale((1 << 19) / 2 / Math.PI)
    .translate([width / 2, height / 2]);

var center = projection([137.025970, 36.754062]);

var path = d3.geo.path()
    .projection(projection);
var zoom = d3.behavior.zoom()
    .scale(projection.scale() * 2 * Math.PI)
    .translate([width - center[0], height - center[1]])
    .on("zoom", redraw);
d3.select("#ex3").select("svg").call(zoom);
projection
    .scale(1 / 2 / Math.PI)
    .translate([0, 0]);


var geoPath = d3.geo.path().projection(projection);
d3.select("#ex3").select("#vectors").selectAll("path.countries").data([takaokaBoundingBox])
    .enter()
    .append("path")
    .attr("d", geoPath)
    .attr("class", "countries")
    .style("fill", "red")
    .style("stroke-width", 3)
    .style("stroke", "black")
    .style("fill-opacity", .25)

redraw();

function redraw() {
   var tiles = tile
        .scale(zoom.scale())
        .translate(zoom.translate())();
    
    var image = d3.select("#ex3").select("#tiles")
        .attr("transform",
        "scale(" + tiles.scale + ") translate(" + tiles.translate + ")")
        .selectAll("image")
        .data(tiles, function(d) { return d; });
    
    image.exit()
       .remove();

    image.enter().append("image")
        .attr("xlink:href",
         function(d) { return "http://" 
             + ["a", "b", "c"][Math.random() * 3 | 0] 
             + ".tile.openstreetmap.org/" + d[2] + "/" + d[0] + "/" + d[1] 
             + ".png"; })        
        .attr("width", 1)
        .attr("height", 1)
        .attr("x", function(d) { return d[0]; })
        .attr("y", function(d) { return d[1]; });
    
        projection
            .scale(zoom.scale() / 2 / Math.PI)
            .translate(zoom.translate());

        d3.select("#ex3").selectAll("path")
            .attr("d", geoPath);
}
Overwriting js/ex7-3.js
In [8]:
%%HTML
<!-- CSSの読み込み -->
<link type="text/css" rel="stylesheet" href="css/ch7.css" />
<!-- 外部jsファイル -->
<script src="js/d3.geo.projection.min.js" type="text/javascript"></script>
<script src="js/colorbrewer.js" type="text/javascript"></script>
<script src="js/tile.js" type="text/javascript"></script>
<script src="js/ex7-3.js" type="text/javascript"></script>


<div id="ex3">
    <div id="viz">
      <svg style="width:500px;height:500px;border:1px lightgray solid;" />
      </svg>
    </div>    
</div>

shpファイルからgeojsonを作成

gdal-binをインストール

$ sudo apt-get install -y gdal-bin
In [9]:
%%bash
# rm -f data/A27-10_16-g_SchoolDistrict.json
ogr2ogr -f geoJSON data/A27-10_16-g_SchoolDistrict.json data/A27-10_16-g_SchoolDistrict.shp
ERROR 6: The GeoJSON driver does not overwrite existing files.
geoJSON driver failed to create data/A27-10_16-g_SchoolDistrict.json
In [10]:
%%writefile js/ex7-4.js
var width = 500, height = 500;
var takaokaBoundingBox = {geometry: {coordinates: [[[136.904778, 36.822525], [137.072662, 36.822525], [137.072662, 36.658552], [136.904778, 36.658552], [136.904778, 36.822525]]], type: "Polygon"}, id: 999999, properties:{}, type: "Feature"};

d3.select("#ex4").select("svg").append("g").attr("id", "tiles");
d3.select("#ex4").select("svg").append("g").attr("id", "vectors");

var tile = d3.geo.tile()
    .size([width, height]);

var projection = d3.geo.mercator()
    .scale((1 << 19) / 2 / Math.PI)
    .translate([width / 2, height / 2]);

var center = projection([137.025970, 36.754062]);

var path = d3.geo.path()
    .projection(projection);
var zoom = d3.behavior.zoom()
    .scale(projection.scale() * 2 * Math.PI)
    .translate([width - center[0], height - center[1]])
    .on("zoom", redraw);
d3.select("#ex4").select("svg").call(zoom);
projection
    .scale(1 / 2 / Math.PI)
    .translate([0, 0]);

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

d3.json('data/A27-10_16-g_SchoolDistrict.json', function (schoolDistnct) {
    // console.log(schoolDistnct);

    var data = schoolDistnct.features.filter(function(d) { 
           return  d.properties.A27_006=="高岡市立"; 
        });

    d3.select("#ex4").select("#vectors").selectAll("path.countries").data(data)
        .enter()
        .append("path")
        .attr("d", geoPath)
        .attr("class", "countries")
        .style("fill", "red")
        .style("stroke-width", 3)
        .style("stroke", "black")
        .style("fill-opacity", .25)   
    
});        

redraw();

function redraw() {
   var tiles = tile
        .scale(zoom.scale())
        .translate(zoom.translate())();
    
    var image = d3.select("#ex4").select("#tiles")
        .attr("transform",
        "scale(" + tiles.scale + ") translate(" + tiles.translate + ")")
        .selectAll("image")
        .data(tiles, function(d) { return d; });
    
    image.exit()
       .remove();

    image.enter().append("image")
        .attr("xlink:href",
         function(d) { return "http://" 
             + ["a", "b", "c"][Math.random() * 3 | 0] 
             + ".tile.openstreetmap.org/" + d[2] + "/" + d[0] + "/" + d[1] 
             + ".png"; })        
        .attr("width", 1)
        .attr("height", 1)
        .attr("x", function(d) { return d[0]; })
        .attr("y", function(d) { return d[1]; });
    
        projection
            .scale(zoom.scale() / 2 / Math.PI)
            .translate(zoom.translate());

        d3.select("#ex4").selectAll("path")
            .attr("d", geoPath);
}
Overwriting js/ex7-4.js
In [11]:
%%HTML
<!-- CSSの読み込み -->
<link type="text/css" rel="stylesheet" href="css/ch7.css" />
<!-- 外部jsファイル -->
<script src="js/d3.geo.projection.min.js" type="text/javascript"></script>
<script src="js/colorbrewer.js" type="text/javascript"></script>
<script src="js/tile.js" type="text/javascript"></script>
<script src="js/ex7-4.js" type="text/javascript"></script>

<div id="ex4">
    <div id="viz">
      <svg style="width:500px;height:500px;border:1px lightgray solid;" />
      </svg>
    </div>    
</div>

geojsonのデータは、以下の図のように各gのdata属性に保持されています。

In [ ]:
 

This website does not host notebooks, it only renders notebooks available on other websites.

Delivered by Fastly, Rendered by Rackspace

nbviewer GitHub repository.

nbviewer version: f697053

nbconvert version: 5.4.1

Rendered (Mon, 20 May 2019 10:58:14 UTC)