Last active
November 8, 2015 19:45
-
-
Save zanarmstrong/a40f50dc6a16844d5346 to your computer and use it in GitHub Desktop.
practicing making a map
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!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> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment