Published
Edited
Oct 31, 2020
Insert cell
Insert cell
chart = {
const links = data3.edges.map(d => Object.create(d));
const nodes = data3.nodes.map(d => Object.create(d));

const simulation = d3
.forceSimulation(nodes)
.force("link", d3.forceLink(links).id(d => d.id))
.force("charge", d3.forceManyBody())
.force("center", d3.forceCenter(width / 2, height / 2));

const svg = d3.create("svg").attr("viewBox", [0, 0, width, height]);
const xScale = d3
.scaleLinear()
.domain([1890, 2020])
.range([0, width]);
const link = svg
.append("g")
.selectAll("line")
.data(links)
.join("path")
.attr("stroke", "#999")
.attr("stroke-opacity", 0.6)
.attr("stroke-width", d => Math.sqrt(d.value));

const nodeGroups = svg
.append('g')
.selectAll("circle")
.data(nodes)
.join("g")
.attr('class', 'node-group');

const nodeCircles = nodeGroups
.append('circle')
.attr("stroke", "#fff")
.attr("stroke-width", 1.5)
.attr("r", ({ size }) => size / 2)
.attr("fill", color)
.call(drag(simulation));

const nodeText = nodeGroups
.append("text")
.attr('class', 'node-text')
.style('opacity', ({ size }) => size / 100)
.text(d => d.id);

simulation.on("tick", () => {
const sourceX = d => (d.source.year ? xScale(d.source.year) : d.source.x);
const targetX = d => (d.target.year ? xScale(d.target.year) : d.source.x);
// link
// .attr("x1", sourceX)
// .attr("y1", d => d.source.y)
// .attr("x2", targetX)
// .attr("y2", d => d.target.y);

link.attr("d", d => {
var dx = targetX(d) - sourceX(d),
dy = d.target.y - d.source.y,
dr = Math.sqrt(dx * dx + dy * dy);
return (
"M" +
sourceX(d) +
"," +
d.source.y +
"A" +
dr +
"," +
dr +
" 0 0,1 " +
targetX(d) +
"," +
d.target.y
);
});

nodeCircles
.attr("cx", d => (d.year ? xScale(d.year) : d.x))
.attr("cy", d => d.y);
nodeText
.attr("x", d => (d.year ? xScale(d.year) : d.x))
.attr("y", d => d.y);
});

invalidation.then(() => simulation.stop());

return svg.node();
}
Insert cell
data3 = JSON.parse(await FileAttachment("filteredData.json").text())
Insert cell
height = 600
Insert cell
color = d => {
return (d.mp && 'orange') || (d.fp && 'blue') || (d.oo && 'red') || 'gray';
}
Insert cell
drag = simulation => {
function dragstarted(event) {
if (!event.active) simulation.alphaTarget(0.3).restart();
event.subject.fx = event.subject.x;
event.subject.fy = event.subject.y;
}
function dragged(event) {
event.subject.fx = event.x;
event.subject.fy = event.y;
}
function dragended(event) {
if (!event.active) simulation.alphaTarget(0);
event.subject.fx = null;
event.subject.fy = null;
}
return d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended);
}
Insert cell
d3 = require("d3@6")
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