Skip to content

Instantly share code, notes, and snippets.

@nl-hugo
Last active April 13, 2017 11:24
Show Gist options
  • Save nl-hugo/3e1999fdda394c7367bb85f3d6f76e51 to your computer and use it in GitHub Desktop.
Save nl-hugo/3e1999fdda394c7367bb85f3d6f76e51 to your computer and use it in GitHub Desktop.
Create a map
height: 650
license: MIT
node_modules
npm-debug.log

A visualisation of the female / male ratio in the Netherlands. A test case to automate download and conversion of CBS maps into a D3.js map.

To reproduce the json file for the map: npm run map

Resources:

Display the source blob
Display the rendered blob
Raw
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
<!DOCTYPE html>
<meta charset="utf-8">
<link href="https://fonts.googleapis.com/css?family=Oxygen:400,700" rel="stylesheet">
<style>
body {
font-size: 10px;
font-family: 'Oxygen', sans-serif;
font-weight: 300;
fill: #aaa;
}
.background {
fill: none;
pointer-events: all;
}
.legend-background {
fill: #fff;
opacity: 0.9;
}
.legend-place {
font-weight: 700;
}
.legend-pointer {
fill:#fff;
fill-opacity: 0.7;
stroke: #ec7014;
}
.domain {
display: none;
}
.tick line {
stroke: #fff;
}
.tick text {
font-size: 9px;
fill: #aaa;
}
.borders {
fill:none;
stroke: #fff;
stroke-width: .5px;
stroke-linejoin: round;
stroke-linecap: round;
pointer-events: none;}
.wijk {
fill:none;
stroke: #ccf;
}
#gemeente {
fill: #eee;
}
.active {
stroke: #ec7014;
}
</style>
<body>
<svg width="700" height="650"></svg>
</body>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://d3js.org/topojson.v1.min.js"></script>
<script>
var svg = d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height"),
margin = {top: 20, right: 30, bottom: 30, left: 40},
legend = {width: 200, height: 12, top: 32, left: 20},
centered;
var projection = d3.geoMercator()
.center([5.4, 52.088]) // Utrecht
.translate([width / 2, height / 2])
.scale(width * 11);
var path = d3.geoPath()
.projection(projection);
var color = d3.scaleLinear().range(['#1f77b4','#e7ccff','#d01c8b']);
var x = d3.scaleLinear().range([0, legend.width / 2 ]);
var defs = svg.append("defs");
var gradient = defs.append("linearGradient")
.attr("id", "linear-gradient");
gradient
.attr("x1", "0%")
.attr("y1", "0%")
.attr("x2", "100%")
.attr("y2", "0%");
svg.append("rect")
.attr("class", "background")
.attr("width", width)
.attr("height", height)
.on("click", clicked);
var g = svg.append("g")
.attr("class", "g-map");
var l = svg.append("g")
.attr("class", "g-legend")
.attr("transform", "translate("+ legend.left + "," + legend.top + ")");
d3.json("gemeente.json", function(error, map) {
if (error) return console.error(error);
var data = topojson.feature(map, map.objects.gem_2016).features;
var colors = d3.extent(data, function(d) { return +d.properties.female / +d.properties.male; });
colors.push(d3.mean(colors));
color.domain(colors.sort());
x.domain(color.domain());
g.append("g")
.attr("id", "gemeente")
.selectAll("path")
.data(data)
.enter().append("path")
.attr("d", path)
.attr("fill", function(d) { return color(+d.properties.female / +d.properties.male); })
.on("click", clicked);
g.append("path")
.datum(topojson.mesh(map, map.objects.gem_2016))
.attr("class", "borders")
.attr("d", path);
// add legend
gradient.selectAll("stop")
.data(color.domain())
.enter().append("stop")
.attr("offset", function(d,i) { return i / (color.domain().length-1); })
.attr("stop-color", function(d) { return color(d); });
l.append("rect")
.attr("class", "legend-background")
.attr("x", -legend.left + 2)
.attr("width", legend.width + 2 * legend.left - 2)
.attr("height", legend.height * 5);
l.append("text")
.attr("class", "legend-title")
.attr("y", 12)
.text("Number of female inhabitants per male in");
l.append("text")
.attr("class", "legend-place")
.attr("y", 25)
.text("The Netherlands");
l.append("rect")
.attr("width", legend.width)
.attr("height", legend.height)
.attr("x", 0)
.attr("y", legend.top)
.style("fill", "url(#linear-gradient)");
l.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(" + 0 + "," + (legend.height + legend.top) + ")")
.call(d3.axisBottom(x)
.tickSize(-legend.height)
.ticks(7)
.scale(x));
var current = l.append("path")
.attr("class", "legend-pointer")
.attr("d", d3.symbol()
.size(30)
.type(d3.symbolCircle))
.attr("transform", "translate(" + x(color.domain()[1]) + "," + (legend.height / 2 + legend.top) + ")");
});
function clicked(d) {
var dx, dy, k, i;
if (d && centered !== d) {
var centroid = path.centroid(d);
dx = centroid[0];
dy = centroid[1];
k = 4;
i = +d.properties.female / +d.properties.male;
centered = d;
} else {
dx = width / 2;
dy = height / 2;
k = 1;
i = color.domain()[1];
centered = null;
}
l.selectAll(".legend-pointer").transition()
.duration(750)
.attr("transform", "translate(" + x(i) + "," + (legend.height / 2 + legend.top) + ")");
l.selectAll(".legend-place")
.text(function(d) { return centered != null ? centered.properties.name : "The Netherlands"; });
g.selectAll("path")
.classed("active", centered && function(d) { return d === centered; });
g.transition()
.duration(750)
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")scale(" + k + ")translate(" + -dx + "," + -dy + ")");
}
</script>
{
"name": "cbs-map",
"version": "0.0.1",
"description": "Female / male ratio",
"keywords": [
"Visualization",
"Map",
"D3.js"
],
"author": "Hugo Janssen <nl-hugo@hugojanssen.nl>",
"private": true,
"license": "MIT",
"devDependencies": {
"download-cli": "~1.0",
"topojson": "~1.6",
"rimraf": "latest",
"ogr2ogr": "1.0.1"
},
"scripts": {
"clean": "rimraf Uitvoer_shape",
"download": "download --extract https://www.cbs.nl/-/media/_pdf/2016/35/shape%202016%20versie%2010.zip",
"shape": "ogr2ogr -f GeoJSON -t_srs EPSG:4326 -where WATER='NEE' Uitvoer_shape/gem_2016.json Uitvoer_shape/gem_2016.shp",
"topojson": "topojson --id-property GM_CODE -p name=GM_NAAM -p inhabitants=AANT_INW -p male=AANT_MAN -p female=AANT_VROUW -s 3e-9 -o gemeente.json -- Uitvoer_shape/gem_2016.json",
"map": "npm run download && npm run shape && npm run topojson && npm run clean"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment