Public
Edited
Jan 29, 2024
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
chart = {
const width = height * aspectRatio;
const svg = d3
.create("svg")
.style("background", "#fff")
.attr("width", width)
.attr("height", height);

svg
.append("rect")
.attr("x", 0)
.attr("y", 0)
.attr("width", width)
.attr("height", height)
.style("fill", "white")
.style("stroke", "black");
const widthChart = width - padding_chart * 2,
heightChart = height - padding_chart * 2;
let cx = widthChart / 2 + padding_chart / 2;
let cy = heightChart / 2 + padding_chart / 2;

const sankey = d3
.sankey()
.nodeId((d) => d.name)
.nodeAlign(d3.sankeyLeft)
.nodeWidth(5)
.nodePadding(padding)
.extent([
[1, 1],
[heightChart, widthChart - 1]
])
.nodeSort((a, b) => d3.descending(a.value, b.value));
const { nodes, links } = sankey({
nodes: data.nodes.map((d) => Object.assign({}, d)),
links: data.links.map((d) => Object.assign({}, d))
});
const plot = svg
.append("g")
.attr("class", "sankey")
.attr(
"transform",
`translate(${padding_chart}, ${
padding_chart * 2
}) rotate(90, ${cx}, ${cy})`
);

const link = plot
.append("g")
.attr("class", "links")
.attr("fill", "none")
.selectAll("g")
.data(links)
.join("g")
.attr("opacity", 0.4)
.attr("stroke", (d) => {
if (!d.color) return "black";
return d.color;
})
.style("mix-blend-mode", "multiply");

link
.append("path")
.attr("d", d3.sankeyLinkHorizontal())
.attr("stroke", (d) => d.uid)
.attr("stroke-width", (d) => Math.max(1, d.width))

plot
.append("g")
.attr("class", "nodes")
.selectAll("rect")
.data(nodes)
.join("rect")
.attr("x", (d) => d.x0)
.attr("y", (d) => d.y0)
.attr("height", (d) => d.y1 - d.y0)
.attr("width", (d) => d.x1 - d.x0)
.attr("stroke", (d) => {
if (d.color === "") return "black";
return d.color;
})
.attr("fill", (d) => {
if (d.color === "") return "black";
return d.color;
});

return svg.node();
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
data = ({
nodes: [
{ name: "All Time" },
{ name: "2023" },
{ name: "2022" },
{ name: "Prior" }
],
links: [
{
source: "All Time",
target: "2023",
value: 1200000
},
{
source: "All Time",
target: "2022",
value: 1800000
},
{
source: "All Time",
target: "Prior",
value: 6700000
}
]
})
Insert cell
// data = {
// const links = d3.csvParseRows(source, ([source, target, value, color]) =>
// source && target
// ? {
// source,
// target,
// value: !value || isNaN((value = +value)) ? 1 : value,
// color
// }
// : null
// );
// const nodeByName = new Map();
// for (const link of links) {
// if (!nodeByName.has(link.source))
// nodeByName.set(link.source, { name: link.source });
// if (!nodeByName.has(link.target))
// nodeByName.set(link.target, { name: link.target });
// }

// const nodes = Array.from(nodeByName.values());

// nodes.forEach((d) => {
// let thisLink = links.filter((e) => e.target === d.name);
// if (thisLink.length === 0)
// thisLink = links.filter((e) => e.source === d.name);
// d.color = thisLink[0].color;
// });
// return { nodes, links };
// }
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