Public
Edited
Nov 28, 2024
Paused
2 forks
15 stars
Insert cell
Insert cell
Insert cell
Insert cell
watercourses = topojson.feature(
await FileAttachment("WatercourseLink.json").json(),
"WatercourseLink"
)
Insert cell
hydroNodes = (await FileAttachment("HydroNode.geojson").json()).features.map(
(d) => ({
id: d.properties.identifier,
type: d.properties.formOfNode
})
)
Insert cell
Insert cell
lakes = topojson.feature(await FileAttachment("lakes.json").json(), "lakes")
Insert cell
Insert cell
function createNodeIds(hNodes) {
return new Set(hNodes.map((d) => d.id));
}
Insert cell
function createEdges(hNodes, wcs) {
const nodeIds = createNodeIds(hNodes);
return new Map(
wcs.features
.filter(
(feat) =>
nodeIds.has(feat.properties.startNode) &&
nodeIds.has(feat.properties.endNode)
)
.map((feat) => [
feat.properties.identifier,
{
id: feat.properties.identifier,
source: feat.properties.startNode,
target: feat.properties.endNode,
name: feat.properties.name1,
type: feat.properties.form
}
])
);
}
Insert cell
Insert cell
function createNodes(hNodes, wcs) {
// Build graph of connected edges
const ns = new Map([...createNodeIds(hNodes)].map((d) => [d, {}]));
const g = new Graph();
for (const edge of createEdges(hNodes, wcs).values()) {
g.addEdge(edge.source, edge.target);
}

// Accumulate Shreve and Strahler order from exterior links inward
g.topologicalSort().forEach((nodeName) => {
const inNodes = g.inNodes(nodeName).map((n) => ns.get(n));
if (inNodes.length === 0) {
return ns.set(nodeName, { strahler: 1, shreve: 1 });
}
const strahler = inNodes.map((n) => n.strahler);
const [min, max] = d3.extent(strahler);
ns.set(nodeName, {
strahler: inNodes.length === 1 || min < max ? max : max + 1,
shreve: d3.sum(inNodes, (n) => n.shreve)
});
});
return ns;
}
Insert cell
Insert cell
function createWatercourses(hNodes, wcs) {
const nodes = createNodes(hNodes, wcs);
const rivers = JSON.parse(JSON.stringify(wcs));
for (const feat of rivers.features) {
feat.properties.strahler = nodes.get(feat.properties.startNode)?.strahler;
feat.properties.shreve = nodes.get(feat.properties.startNode)?.shreve;
}
return rivers;
}
Insert cell
Insert cell
Plot.plot({
width: 780,
height: 900,
projection: {
type: "reflect-y",
domain: new GeoJSON()
.points([
[300000, 480000],
[360000, 550000]
])
.boundingRect()
},
marks: [
Plot.geo(createWatercourses(hydroNodes, watercourses), {
strokeWidth: (d) => 0.2 + Math.log(d.properties.shreve) / 4,
stroke: "steelblue"
}),
Plot.geo(lakes, {
stroke: "steelBlue",
strokeWidth: 0.5,
fill: "rgb(198,223,245)"
})
]
})
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more