Skip to content

Instantly share code, notes, and snippets.

@zanarmstrong
Last active November 8, 2015 19:45
Show Gist options
  • Save zanarmstrong/a40f50dc6a16844d5346 to your computer and use it in GitHub Desktop.
Save zanarmstrong/a40f50dc6a16844d5346 to your computer and use it in GitHub Desktop.
practicing making a map
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/
<!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="http://d3js.org/d3.v3.min.js"></script>
<script src="http://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)
// remove other territories from naming, etc
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}
});
// define our projection - and where to crop the world
var projection = d3.geo.albers()
.center([15, 63])
.rotate([0, 0])
.parallels([65, 70])
.scale(3000)
.translate([width / 2, height / 2]);
// generate path, using the albers projection defined above
var path = d3.geo.path()
.projection(projection);
// draw paths, note that this still includes things like svalbard,
// but it's out of the range of the map
svg.append("path")
.datum(subunits)
.attr("d", path);
// define sub-units, so that we can use classes to style
svg.selectAll(".subunit")
.data(featureData)
.enter().append("path")
.attr("class", function(d) { return "subunit " + d.id; })
.attr("d", path);
// define the boundary of countries so we can style
svg.append("path")
.datum(featureData)
.attr("d", path)
.attr("class", "subunit-boundary");
// introduce places (cities)
svg.append("path")
.datum(topojson.feature(sweden, sweden.objects.places))
.attr("d", path)
.attr("class", "place");
// label the cities
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; });
// locate the labels
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"; });
// label the countries
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>
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment