Published
Edited
Aug 31, 2021
2 forks
Importers
9 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
ethereal = ethereal_hexbin(radius)
Insert cell
function ethereal_hexbin(radius) {
const hex = d3
.hexbin()
.radius(radius)
.size([width, height]);

return hex(pts.concat(hex.centers()))
.filter(d => d.length === 1)
.map(d => [d.x, d.y]);
}
Insert cell
function map(anchor) {
const context = DOM.context2d(width, height),
path = d3.geoPath().context(context);

// underlying graph
context.beginPath();
for (let k = 0; k < graph.sources.length; k++) {
const i = graph.sources[k],
j = graph.targets[k];
if (i < j) {
context.moveTo(...pts[i]);
context.lineTo(...pts[j]);
}
}
context.strokeStyle = "#ccc";
context.lineWidth = 1;
context.stroke();

for (let i = 0; i < origins.length; i++) {
const c = d3
.tricontour()
.value((d, j) => (tree.origin[j] === origins[i] ? 1 : 0))
.contour(pts.concat(anchor.includes("use") ? ethereal : []), 0.5);

context.beginPath();
path(c);
context.globalAlpha = 0.2;
context.strokeStyle = context.fillStyle = color(origins[i]);
context.fill();
context.globalAlpha = 1;
}

if (anchor.includes("show")) {
context.beginPath();
path.pointRadius(1);
path({ type: "MultiPoint", coordinates: ethereal });
context.fillStyle = "#888";
context.fill();
}

// the trees
context.lineWidth = 2;
for (const k of origins) {
context.beginPath();
context.strokeStyle = color(k);
for (let i = 0; i < pts.length; i++) {
const j = tree.predecessor[i];
if (j > -1 && tree.origin[j] === k) {
context.moveTo(...pts[i]);
context.lineTo(...pts[j]);
}
}
context.stroke();
}

path.pointRadius(6);
for (const k of origins.filter(i => i < pts.length)) {
context.beginPath();
path({
type: "Point",
coordinates: pts[k]
});
context.fillStyle = color(k);
context.strokeStyle = "white";
context.fill();
context.stroke();
}

return context.canvas;
}
Insert cell
Insert cell
origins = Array.from({ length }, () => (Math.random() * nodes.length) | 0)
Insert cell
Insert cell
Insert cell
src = "https://gist.githubusercontent.com/Fil/450db51a15fdc8bd34a12cb8a9961976/raw/680961da57d2b11a0e3e6993e5f79bd035729831"
Insert cell
nodes = d3.csv(`${src}/node_list.csv`, d3.autoType)
Insert cell
edges = d3.csv(`${src}/edge_list.csv`, d3.autoType)
Insert cell
Insert cell
nodesIndex = new Map(nodes.map((d, i) => [d.osmid, i]))
Insert cell
function createGraph(nodesIndex, edges) {
const graph = { sources: [], targets: [], costs: [] };
edges.forEach(({ u, v, length }) => {
const i = nodesIndex.get(u),
j = nodesIndex.get(v),
cost = length;
graph.sources.push(i);
graph.targets.push(j);
graph.costs.push(cost);

graph.sources.push(j);
graph.targets.push(i);
graph.costs.push(cost);
});

return graph;
}
Insert cell
graph = createGraph(nodesIndex, edges)
Insert cell
import { shortest_tree } from "@fil/dijkstra"
Insert cell
tree = shortest_tree({ graph, origins })
Insert cell
Insert cell
pts = nodes.map(d => projection([d.x, d.y]))
Insert cell
projection = d3.geoMercator().fitExtent([[10, 10], [width - 10, height - 10]], {
type: "MultiPoint",
coordinates: nodes.map(d => [d.x, d.y])
})
Insert cell
Insert cell
color = d3.scaleOrdinal(d3.schemeCategory10)
Insert cell
Insert cell
d3 = require("d3@5", "d3-tricontour@1", "d3-hexbin@0.2")
Insert cell
import { checkbox, slider } from "@jashkenas/inputs"
Insert cell
height = width * 0.9
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