Public
Edited
Jul 19, 2024
Insert cell
Insert cell
chart = {
// Specify the dimensions of the chart.
const width = 928;
const height = 680;

// Specify the color scale.
const color = d3.scaleOrdinal(d3.schemeCategory10);

// The force simulation mutates links and nodes, so create a copy
// so that re-evaluating this cell produces the same result.
const links = data.links.filter((d) => d.target).map((d) => ({ ...d }));
const nodes = data.nodes.map((d) => ({ ...d }));

// Create a simulation with several forces.
const simulation = d3
.forceSimulation(nodes)
.force(
"link",
d3.forceLink(links).id((d) => d.id)
)
.force("charge", d3.forceManyBody().strength(-100))
.force(
"x",
d3
.forceX((d) => {
// if (d.type === "dirpath") {
// return d.origin === "cmip6plus" ? 100 : -100;
// } else {
// return 0;
// }
if (d.id === "cmip6plus") return 100;
if (d.id === "mip-cmor-tables") return -100;
return 0;
})
.strength((d) => {
if (d.id === "cmip6plus") return 0.1;
if (d.id === "mip-cmor-tables") return 0.1;
return 0.2;
})
// .strength(1)
)
.force("y", d3.forceY());

// Create the SVG container.
const svg = d3
.create("svg")
.attr("width", width)
.attr("height", height)
.attr("viewBox", [-width / 2, -height / 2, width, height])
.attr("style", "max-width: 100%; height: auto;");

// Add a line for each link
const link = svg
.append("g")
.attr("stroke", "#999")
.attr("stroke-opacity", 0.6)
.selectAll("line")
.data(links)
.join("line")
.attr("stroke-width", (d) => Math.sqrt(d.value));

// Add a group for each node
const node = svg
.append("g")
.attr("stroke", "#fff")
.attr("stroke-width", 1.5)
.selectAll("g")
.data(nodes)
.join("g")
.call(
d3
.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended)
);

// Add a circle to each node group
node
.append("circle")
.attr("r", (d) => 1 + d.weight ** 0.4)
.attr("fill", (d) => color(d.origin));

// Add a text label to each node group
// node
// .append("text")
// .text((d) => d.id)
// .attr("font-size", "10px")
// .attr("dx", 12)
// .attr("dy", 4);

node.append("title").text((d) => d.id);

// Add text labels for links
const linkLabels = svg
.append("g")
.attr("class", "link-labels")
.selectAll("text")
.data(links)
.join("text")
.text((d) => d.value) // Assuming you want to display the 'value' property
.attr("font-size", "8px")
.style("fill", "#666!important");

// Set the position attributes of links and nodes each time the simulation ticks.
simulation.on("tick", () => {
link
.attr("x1", (d) => d.source.x)
.attr("y1", (d) => d.source.y)
.attr("x2", (d) => d.target.x)
.attr("y2", (d) => d.target.y);

node.attr("transform", (d) => `translate(${d.x},${d.y})`);

// linkLabels
// .attr("x", (d) => (d.source.x + d.target.x) / 2)
// .attr("y", (d) => (d.source.y + d.target.y) / 2);
});

// Reheat the simulation when drag starts, and fix the subject position.
function dragstarted(event) {
if (!event.active) simulation.alphaTarget(0.3).restart();
event.subject.fx = event.subject.x;
event.subject.fy = event.subject.y;
}

// Update the subject (dragged node) position during drag.
function dragged(event) {
event.subject.fx = event.x;
event.subject.fy = event.y;
}

// Restore the target alpha so the simulation cools after dragging ends.
// Unfix the subject position now that it's no longer being dragged.
function dragended(event) {
if (!event.active) simulation.alphaTarget(0);
event.subject.fx = null;
event.subject.fy = null;
}

// When this cell is re-run, stop the previous simulation.
invalidation.then(() => simulation.stop());

return svg.node();
}
Insert cell
data = FileAttachment("graph@6.json").json()
Insert cell
Insert cell

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more