Public
Edited
Feb 27
1 fork
17 stars
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
tesselation = new delaunay.Delaunay(nodes.flatMap((d) => [d.x, d.y]))
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
borderDistricts = new Set(
btw2025Epsg3035MediumTopo.objects.wahlkreise.geometries
.filter((d) => {
const arcs = d.arcs.flat(3).map((a) => (a < 0 ? ~a : a));
return arcs.some((arc) => {
const districts = arc2district[arc].filter(
(id) => id != d.properties.wkr_id
);
return !districts.length;
});
})
.map((d) => d.properties.wkr_id)
)
Insert cell
Insert cell
Insert cell
freeBorderDistricts = [87, 55, 6, 299, 283]
Insert cell
fixedDistricts = ({
112: { x: 4090672, y: 3189879 },
125: { x: 4106755, y: 3215482 },
123: { x: 4126026, y: 3239874 },
86: { x: 4047474, y: 3079430 },
197: { x: 4129801, y: 3005003 }
})
Insert cell
Insert cell
Insert cell
Insert cell
data = {
const free = new Set(freeBorderDistricts);
return {
nodes: nodes.map((n) => ({
...n,
origX: n.x,
origY: n.y,
...(fixedDistricts[n.wkr_id] ||
(borderDistricts.has(n.wkr_id) && !free.has(n.wkr_id))
? {
fx: fixedDistricts[n.wkr_id]?.x ?? n.x,
fy: fixedDistricts[n.wkr_id]?.y ?? n.y
}
: {})
})),
links: edges.map((d) => ({
source: nodes.findIndex((n) => n.wkr_id === d.source.wkr_id),
target: nodes.findIndex((n) => n.wkr_id === d.target.wkr_id)
}))
};
}
Insert cell
Insert cell
layout = {
const height = width;
const links = data.links.map((d) => Object.create(d));
const nodes = data.nodes.map((d) => Object.create(d));

let out = { nodes, links };

return new Promise((resolve) => {
const simulation = d3
.forceSimulation(nodes)
.alphaDecay(0.015)
.force("charge", d3.forceManyBody().strength(-30))
.force(
"link",
d3
.forceLink(links)
.strength(0.9)
.distance((link) => {
return link.source.bl === link.target.bl ? 3 : 1000;
})
.iterations(20)
)
.force(
"collide",
d3.forceCollide(nodes).radius(radius).iterations(10).strength(1.4)
)
.on("tick", () => {
out.nodes = nodes;
})
.on("end", () => {
resolve({ nodes, links });
});

invalidation.then(() => simulation.stop());
});
}
Insert cell
Insert cell
Insert cell
btw2025Epsg3035MediumTopo = FileAttachment("btw-2025-epsg3035-medium.topo.json").json()
Insert cell
topojson = require("topojson-client")
Insert cell
delaunay = require("d3-delaunay")
Insert cell
Insert cell
dsv = require("d3-dsv")
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