#30DayMapChallenge Day 2. Lines
Autumn – coloring streams by their flow order in QGIS ๐
Here’s one of the maps I have made for the #30DayMapChallenge on Twitter in 2021. You can find out more about the challenge and my other maps in this post.
Goal: A map with lines.
Live: https://maptheclouds.com/playground/30-day-map-challenge/lines/
Tweet: https://twitter.com/maptheclouds/status/1455593450720595984
Code: https://github.com/alexaac/map-challenges/tree/master/lines
Description:
The visualization shows the Yosemite Valley river network and catchment area, and is made by coloring streams by their flow order in QGIS.
Data: OpenTopography
Tags: #D3js #QGIS #mapshaper #canvas #LiDAR #hidrology #river #channels
Inspiration:
https://observablehq.com/@jipexu/chinese-rivers
https://www.youtube.com/watch?v=xwiHQlmEEjw
https://angrytools.com/gradient/
Challenges: For this map, I already had a elevation model surface for Yosemite derived from LiDAR files downloaded from OpenTopography.
I got the chance to make some GIS analysis in QGIS, play with styling and gradients in JavaScript and CSS, and display the result in the browser.
I have used QGIS to extract the river network (you can watch a tutorial that explains how to do this, ‘Deriving River Network & Catchments from a DEM using QGIS’), and mapped it in the browser using D3.js and Canvas.
What is interesting about the map is the leaves effect, from setting a fillStyle to the river lines, and the sky gradient. I have coloured the leaves by stream order, except for the main river.
// Color scale
colorScale = d3
.scaleQuantile()
.domain([0, 1, 2, 3, 4, 5, 6, 7])
.range([
'#1b251d',
'#403310',
'#8e6035',
'#99700a',
'#ad8a38',
'#be903b',
'#feef8b',
]);
[...]
if (river.properties.ORDER > 1) {
context.fillStyle = colorScale(river.properties.ORDER);
context.fill();
}
I have created gradients for three elements on the page, in the title, for the legend and as a background for the map.
Here’s how I have obtained the gradient in the title, as background for the unicode symbol, with CSS:
.sky {
padding: 0.5rem;
/* ff 3.6+ */
background: -moz-radial-gradient(
ellipse at 91% 15%,
#67afee 0%,
#158fc2 25%,
#288ce2 50%,
#096cc4 75%,
#1262ad 100%
);
/* safari 5.1+,chrome 10+ */
background: -webkit-radial-gradient(
ellipse at 91% 15%,
#67afee 0%,
#158fc2 25%,
#288ce2 50%,
#096cc4 75%,
#1262ad 100%
);
/* opera 11.10+ */
background: -o-radial-gradient(
ellipse at 91% 15%,
#67afee 0%,
#158fc2 25%,
#288ce2 50%,
#096cc4 75%,
#1262ad 100%
);
/* ie 10+ */
background: -ms-radial-gradient(
ellipse at 91% 15%,
#67afee 0%,
#158fc2 25%,
#288ce2 50%,
#096cc4 75%,
#1262ad 100%
);
/* global 92%+ browsers support */
background: radial-gradient(
ellipse at 91% 15%,
#67afee 0%,
#158fc2 25%,
#288ce2 50%,
#096cc4 75%,
#1262ad 100%
);
}
Here is the code for creating the gradient for the legend, with D3.js:
// Add sky gradient
const defs = svg.append('defs');
const gradient = defs
.append('radialGradient')
.attr('id', 'svgGradient')
.attr('cx', '50%')
.attr('cy', '50%')
.attr('r', '50%')
.attr('y1', '0%');
gradient
.append('stop')
.attr('offset', '0%')
.attr('style', 'stop-color:rgb(21,143,194);stop-opacity:1.00');
gradient
.append('stop')
.attr('offset', '50%')
.attr('style', 'stop-color:rgb(40,140,226);stop-opacity:1.00');
mapLegend
.append('rect')
.attr('x', 0)
.attr('y', -20)
.attr('width', 150)
.attr('height', 300)
.style('fill', 'url(#svgGradient)')
.style('stroke', '#dddddd');
And here is the code for creating the map background:
// Background
const grad = context.createRadialGradient(408, 216, 0, 408, 216, 427.8);
grad.addColorStop(0, 'rgba(103, 175, 238, 1)');
grad.addColorStop(0.25, 'rgba(21, 143, 194, 1)');
grad.addColorStop(0.5, 'rgba(40, 140, 226, 1)');
grad.addColorStop(0.75, 'rgba(9, 108, 196, 1)');
grad.addColorStop(1, 'rgba(18, 98, 173, 1)');
context.fillStyle = grad;
context.fillRect(0, 0, width, height);
Initially, you could zoom and pan, but because the file was too large, it was loading slowly, and I didn’t want to handle this, I have added a fallback static image on the page. If you have patience, maybe you will se the interactive map on the page, too, after a while. ๐
TODO: create tiles and show details by zoom level, fix pan.