Shaded relief map of Wisconsin.
The recipe for creating the shaded relief raster image came largely from Thomas Thoren's great blog post Making a New York Times Map. Derek Watkin's GDAL cheat sheet and SRTM Tile Grabber were also very useful.
This recipe is in the two bash scripts in this gist repo.
First, make-borders.sh
creates the Wisconsin state and county borders
vector data. Second, make-shaded-relief.sh
creates the shaded relief
raster data from NASA's STRM data.
The scripts need to be run in that order. The borders data is used to
clip the raster data.
xxxxxxxxxx
<html>
<head>
<style>
label {
position: absolute;
top: 15px;
right: 15px;
font-family: sans-serif;
font-size: 12px;
}
.state-interior {
fill: #fff;
}
.state-border {
fill: none;
stroke: lightslategrey;
}
.raster {
pointer-events: none;
fill: none;
}
.charcoalified .state-interior {
fill: #000;
}
.charcoalified .state-border {
stroke: none;
}
</style>
</head>
<body>
<label>
<input type="checkbox">
Charcoalify
</label>
<script src="https://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<script src="//d3js.org/topojson.v1.min.js"></script>
<script>
var width = 960,
height = 1000;
// Path generator that works with preprojected geo data
// (see https://bl.ocks.org/mbostock/5663666)
var path = d3.geo.path()
.projection(matrix(1, 0, 0, -1, 0, height))
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
d3.json("wi.json", function(error, wi) {
if (error) throw error;
var counties = topojson.feature(wi, wi.objects.counties),
state = topojson.merge(wi, wi.objects.counties.geometries);
// Fit the geography to the canvas (i.e., scale and translate)
var b = path.bounds(counties),
s = .975 / Math.max((b[1][0] - b[0][0]) / width, (b[1][1] - b[0][1]) / height),
t = [(width - s * (b[1][0] + b[0][0])) / 2, (height - s * (b[1][1] + b[0][1])) / 2];
path.projection(matrix(s, 0, 0, -s, t[0], t[1]));
// Draw state interior
svg.append("path").datum(state)
.attr("class", "state-interior")
.attr("d", path);
// Draw shaded relief from raster data
var raster_width = (b[1][0] - b[0][0]) * s;
var raster_height = (b[1][1] - b[0][1]) * s;
var rtranslate_x = (width - raster_width) / 2;
var rtranslate_y = (height - raster_height) / 2;
svg.append("image")
.attr("xlink:href", "shaded-relief.png")
.attr("class", "raster")
.attr("width", raster_width)
.attr("height", raster_height)
.attr("transform",
"translate(" + rtranslate_x + ", " + rtranslate_y + ")");
// Draw state border from vector data
// (drawn after raster so it overlays)
svg.append("path").datum(state)
.attr("class", "state-border")
.attr("d", path);
// TODO: The raster data and vector data don't match up perfectly here
// This may be due to the fact that this state border is from merged
// county data and the raster image was clipped to a state border from
// a different vector file. May also be due to the projection issues.
});
// Charcoalify checkbox
var charcoalified = false;
d3.select("input")
.on("change", function() {
svg.classed("charcoalified", charcoalified = !charcoalified);
});
function matrix(a, b, c, d, tx, ty) {
return d3.geo.transform({
point: function(x, y) { this.stream.point(a * x + b * y + tx, c * x + d * y + ty); }
});
}
</script>
</body>
</html>
https://d3js.org/d3.v3.min.js
https://d3js.org/topojson.v1.min.js