index.html
<!DOCTYPE html>
<meta charset="utf-8">
<style>
.subunit.SWE { fill: #8fb1e6; }
.subunit.NOW { fill: white; }
.subunit.FIN { fill: white; }
.subunit.DNK { fill: white; }
.subunit.DNB { fill: white; }
.place,
.place-label {
fill: #444;
}
.subunit-label {
fill: black;
fill-opacity: .5;
font-size: 20px;
font-weight: 300;
text-anchor: middle;
}
.subunit-boundary {
fill: none;
stroke: #777;
}
text {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 10px;
pointer-events: none;
}
</style>
<body>
<script src="//d3js.org/d3.v3.min.js"></script>
<script src="//d3js.org/topojson.v1.min.js"></script>
<script>
var width = 960,
height = 1160;
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
d3.json("scandinavia.json", function(error, sweden) {
if (error) return console.error(error);
var subunits = topojson.feature(sweden, sweden.objects.subunits)
var featureData = topojson.feature(sweden, sweden.objects.subunits).features
.filter(function(d){
if (Array('DNK', 'FIN', 'NOW', 'SWE', 'DNB').indexOf(d.id)> -1){return d}
});
var projection = d3.geo.albers()
.center([15, 63])
.rotate([0, 0])
.parallels([65, 70])
.scale(3000)
.translate([width / 2, height / 2]);
var path = d3.geo.path()
.projection(projection);
svg.append("path")
.datum(subunits)
.attr("d", path);
svg.selectAll(".subunit")
.data(featureData)
.enter().append("path")
.attr("class", function(d) { return "subunit " + d.id; })
.attr("d", path);
svg.append("path")
.datum(featureData)
.attr("d", path)
.attr("class", "subunit-boundary");
svg.append("path")
.datum(topojson.feature(sweden, sweden.objects.places))
.attr("d", path)
.attr("class", "place");
svg.selectAll(".place-label")
.data(topojson.feature(sweden, sweden.objects.places).features)
.enter().append("text")
.attr("class", "place-label")
.attr("transform", function(d) {return "translate(" + projection(d.geometry.coordinates) + ")"; })
.attr("dy", ".35em")
.text(function(d) { return d.properties.name; });
svg.selectAll(".place-label")
.attr("x", function(d) { return d.geometry.coordinates[0] > 15.8 ? 6 : -6; })
.style("text-anchor", function(d) { return d.geometry.coordinates[0] > 15.8 ? "start" : "end"; });
svg.selectAll(".subunit-label")
.data(featureData.filter(function(d) {if(d.id != 'DNB'){return d}}))
.enter().append("text")
.attr("class", function(d) {return "subunit-label " + d.id; })
.attr("transform", function(d) {
var centerLabel = path.centroid(d);
if(d.id == 'NOW'){centerLabel = [centerLabel[0] - 30, centerLabel[1] + 130]};
if(d.id == 'SWE'){centerLabel = [centerLabel[0] - 30, centerLabel[1] + 15]};
console.log(centerLabel, path.centroid(d), d)
return "translate(" + centerLabel + ")"; })
.attr("dy", ".35em")
.text(function(d) {return d.properties.name; });
});
</script>
README.txt
Goal: practice getting data from other sources and making a map using d3 and topo.json
Code adapted from Mike Bostock's example: "Let's make a map": http://bost.ocks.org/mike/map/.
Much of the code was copied directly.
Adapted where appropriate to get data about Scandinavia and to highlight only Sweden on the map.
One challenge was handling the many very small territories under Scandinavian rule around the world,
with different country codes.
Source data from Natural Earth Data: http://www.naturalearthdata.com/
ogr2ogr from GDAL and topoJSON from node.js were used to process data.
# to select only Swedish place names
ogr2ogr \
-f GeoJSON \
-where "ISO_A2 IN ('SE')" \
places.json \
ne_10m_populated_places.shp
# to get geo data for Sweden, Norway, Denmark, and Finland
ogr2ogr \
-f GeoJSON \
-where "ADM0_A3 IN ('SWE', 'NOR', 'DNK', 'FIN')" \
subunits.json \
ne_10m_admin_0_map_subunits.shp
# to combine that two files into one
topojson \
-o scandinavia.json \
--id-property SU_A3 \
--properties name=NAME \
-- \
subunits.json \
places.json
Note that original dbf files are corrupted for non-English characters. In this instance, I corrected the spellings manually. More information here: http://www.naturalearthdata.com/forums/topic/bad-adm1name-encoding-in-version-3-0-0-and-missing-diacritics-in-name/