Skip to content

Instantly share code, notes, and snippets.

@ThomasThoren
Last active December 19, 2022 04:45
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save ThomasThoren/550b2ce8b1e2470e75b2 to your computer and use it in GitHub Desktop.
Save ThomasThoren/550b2ce8b1e2470e75b2 to your computer and use it in GitHub Desktop.
Shaded relief map
<!DOCTYPE html>
<html>
<head>
<title>Shaded relief</title>
<meta charset="utf-8">
<style>
body {
padding: 0;
margin: 0;
}
.parishes {
fill: none;
stroke: white;
stroke-width: 1px;
stroke-opacity: 1;
}
.raster {
fill: none;
opacity: 1;
}
.country-border {
fill: none;
stroke: red;
stroke-width: 5px;
stroke-opacity: 0.7;
}
</style>
</head>
<body>
<svg id="map"></svg>
<script src="//d3js.org/d3.v3.min.js"></script>
<script src="//d3js.org/queue.v1.min.js"></script>
<script src="//d3js.org/topojson.v1.min.js"></script>
<script>
var map_width = 600,
map_height = 600;
var svg = d3.select("#map")
.attr("width", map_width)
.attr("height", map_height);
var la_vector_projection = d3.geo.mercator()
.scale(1)
.translate([0, 0]);
var la_vector_path = d3.geo.path()
.projection(la_vector_projection);
queue()
.defer(d3.json, "louisiana.json")
.await(ready);
function ready(error, louisiana) {
if (error) throw error;
var parishes = topojson.feature(louisiana, louisiana.objects.louisiana);
var b = la_vector_path.bounds(parishes),
s = 1 / Math.max((b[1][0] - b[0][0]) / map_width, (b[1][1] - b[0][1]) / map_height),
t = [(map_width - s * (b[1][0] + b[0][0])) / 2, (map_height - s * (b[1][1] + b[0][1])) / 2];
// Update the projection to use computed scale & translate.
la_vector_projection
.scale(s)
.translate(t);
// Raster
var raster_width = (b[1][0] - b[0][0]) * s;
var raster_height = (b[1][1] - b[0][1]) * s;
var rtranslate_x = (map_width - raster_width) / 2;
var rtranslate_y = (map_height - raster_height) / 2;
// Shaded relief, Louisiana
// svg.append("clipPath")
// .attr("id", "la_clip")
// .append("use")
// .attr("xlink:href", "#louisiana");
svg.append("image")
.attr("clip-path", "url(#la_clip)")
.attr("xlink:href", "louisiana-crop.png")
.attr("class", "raster")
.attr("width", raster_width)
.attr("height", raster_height)
.attr("transform", "translate(" + rtranslate_x + ", " + rtranslate_y + ")");
// svg.append("use")
// .attr("xlink:href", "#louisiana");
// Draw parishes
svg.append("path")
.datum(parishes)
.datum(parishes, function(a, b) { return a !== b; })
.attr("class", "parishes")
.attr("id", "louisiana") // For shaded relief
.attr("d", la_vector_path);
}
// Allows iframe on bl.ocks.org.
d3.select(self.frameElement).style("height", map_height + "px");
</script>
</body>
</html>
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.
.PHONY: all clean
.SECONDARY:
# Download 90-meter SRTM tiles for Louisiana
zip/srtm_%.zip:
@mkdir -p $(dir $@)
@curl -sS -o $@.download 'http://srtm.csi.cgiar.org/SRT-ZIP/SRTM_V41/SRTM_Data_GeoTiff/$(notdir $@)'
@mv $@.download $@
zip/tl_2015_us_county.zip:
@mkdir -p $(dir $@)
@curl -sS -o $@.download 'ftp://ftp2.census.gov/geo/tiger/TIGER2015/COUNTY/$(notdir $@)'
@mv $@.download $@
# Unzip
tif/srtm_%.tif: zip/srtm_%.zip
@mkdir -p $(dir $@)
@rm -rf tmp && mkdir tmp
@unzip -q -o -d tmp $<
@cp tmp/* $(dir $@)
@rm -rf tmp
shp/tl_2015_us_county.shp: zip/tl_2015_us_county.zip
@mkdir -p $(dir $@)
@rm -rf tmp && mkdir tmp
@unzip -q -o -d tmp $<
@cp tmp/* $(dir $@)
@rm -rf tmp
# Extract Louisiana from U.S.
shp/louisiana.shp: shp/tl_2015_us_county.shp
@mkdir -p $(dir $@)
@ogr2ogr \
-f 'ESRI Shapefile' \
-t_srs "EPSG:4326" \
$@ $< \
-dialect sqlite \
-sql "SELECT Geometry, \
STATEFP \
FROM tl_2015_us_county \
WHERE STATEFP = '22'"
# Convert to GeoJSON
geojson/louisiana.json: shp/louisiana.shp
@mkdir -p $(dir $@)
@ogr2ogr \
-f 'GeoJSON' \
$@ $<
# Convert to TopoJSON
topojson/louisiana.json: geojson/louisiana.json
@mkdir -p $(dir $@)
@topojson \
--properties \
--no-quantization \
-o $@ \
-- $<
# Simplify TopoJSON
louisiana.json: topojson/louisiana.json
@mkdir -p $(dir $@)
@topojson \
--properties \
--spherical \
-q 1e8 \
-s 1e-10 \
-o $@ \
-- $<
# Merge tiles
tif/louisiana-merged.tif: \
tif/srtm_17_07.tif \
tif/srtm_18_07.tif \
tif/srtm_19_07.tif \
tif/srtm_17_06.tif \
tif/srtm_18_06.tif \
tif/srtm_19_06.tif \
tif/srtm_17_05.tif \
tif/srtm_18_05.tif \
tif/srtm_19_05.tif
@mkdir -p $(dir $@)
@gdal_merge.py \
-o $@ \
-init "255" \
tif/srtm_*.tif
# Convert to Mercator, from WGS 84
tif/louisiana-reprojected.tif: tif/louisiana-merged.tif
@mkdir -p $(dir $@)
@gdalwarp \
-co "TFW=YES" \
-s_srs "EPSG:4326" \
-t_srs "EPSG:3857" \
$< \
$@
# Crop to Louisiana shape
tif/louisiana-cropped.tif: tif/louisiana-reprojected.tif shp/louisiana.shp
@mkdir -p $(dir $@)
@# Use nodata=255 to ignore white.
@gdalwarp \
-cutline shp/louisiana.shp \
-crop_to_cutline \
-dstalpha \
-srcnodata 255 \
-dstnodata 255 \
tif/louisiana-reprojected.tif $@
tif/louisiana-color-crop.tif: tif/louisiana-cropped.tif
@rm -rf tmp && mkdir -p tmp
@gdaldem \
hillshade \
$< tmp/hillshade.tmp.tif \
-z 5 \
-az 315 \
-alt 60 \
-compute_edges
@gdal_calc.py \
-A tmp/hillshade.tmp.tif \
--outfile=$@ \
--calc="255*(A>220) + A*(A<=220)"
@gdal_calc.py \
-A tmp/hillshade.tmp.tif \
--outfile=tmp/opacity_crop.tmp.tif \
--calc="1*(A>220) + (256-A)*(A<=220)"
@rm -rf tmp
tif/louisiana-color.tif: tif/louisiana-reprojected.tif
@rm -rf tmp && mkdir -p tmp
@gdaldem \
hillshade \
$< tmp/hillshade.tmp.tif \
-z 5 \
-az 315 \
-alt 60 \
-compute_edges
@gdal_calc.py \
-A tmp/hillshade.tmp.tif \
--outfile=$@ \
--calc="255*(A>220) + A*(A<=220)"
@gdal_calc.py \
-A tmp/hillshade.tmp.tif \
--outfile=tmp/opacity_crop.tmp.tif \
--calc="1*(A>220) + (256-A)*(A<=220)"
@rm -rf tmp
louisiana-crop.png: tif/louisiana-color-crop.tif
@convert \
-resize x670 \
$< $@
louisiana.png: tif/louisiana-color.tif
@convert \
-resize x670 \
$< $@
clean:
@rm -f *.json louisiana*.png
@rm -rf geojson
@rm -rf shp
@rm -rf tif
@rm -rf topojson
all: louisiana.png \
louisiana-crop.png \
louisiana.json
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment