graph = {
const svg = d3.select(DOM.svg(width, height));
let link = svg
.append("g")
.attr("class", "links")
.attr("fill", "none")
.attr("stroke", "#f05440")
.attr("stroke-opacity", 0.9)
.selectAll("path");
let node = svg
.append("g")
.attr("class", "nodes")
.attr("font-family", "sans-serif")
.attr("font-size", 14)
.selectAll("g");
sankey(data);
link = link
.data(data.links)
.enter()
.append("path")
.attr("d", d3Sankey.sankeyLinkHorizontal())
.attr("opacity", 0.5)
.attr("stroke-width", (d) => Math.max(1, d.width))
.attr("stroke", (d) =>
(d.source.name + d.target.name).includes("dog") ? dogColor : catColor
);
link.append("title").text((d) => `${d.source.name} → ${d.target.name}`);
node = node.data(data.nodes).enter().append("g");
node
.append("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("fill", "#283250");
node
.append("text")
.attr("x", (d) => d.x0 - 6)
.attr("y", (d) => (d.y1 + d.y0) / 2)
.attr("fill", "#283250")
.attr("dy", "0.35em")
.attr("text-anchor", "end")
.text((d) => d.name)
.filter((d) => d.x0 < width / 2)
.attr("x", (d) => d.x1 + 6)
.attr("text-anchor", "start");
node.append("title").text((d) => `${d.name}`);
return svg.node();
}