1

In my project I draw a sankey graph with d3.js version 6.2.0 and d3-sankey version 0.12.3. The result is in the following screenshot.

enter image description here

In the source file I have some groups

{
  "nodes": [
    {
      "group_nodes": "1st line",
      "name": "CL",
      "id": 0
    },
    {
      "group_nodes": "2nd line",
      "name": "COMT, CL, DA",
      "id": 9
    },
    {
      "group_nodes": "3rd line",
      "name": "COMT",
      "id": 39
    }
  ],
  "links": [
  ]
}

What I want to achieve is to align each group in one column. For example, all group 1 on the left, group 2 in the middle of the graph and the group 3 on the right.

enter image description here

function DrawSankey() {
    d3.json("../data.json").then(function (sankeydata) {
        graph = sankey(sankeydata);

        // add in the links
        var link = svg.append('g').selectAll('.link')
            .data(graph.links)
            .enter().append('path')
            .attr('class', 'link')
            .attr("d", d3.sankeyLinkHorizontal())
            .style('stroke-width', 5)  // d => Math.max(10, d.dy)
            .style('fill', 'none')
            .style('stroke-opacity', 0.4)
            .sort((a, b) => b.dy - a.dy)
            .on('mouseover', function () {
                d3.select(this).style('stroke-opacity', 0.6);
            })
            .on('mouseout', function () {
                d3.select(this).style('stroke-opacity', 0.4);
            });

        // add the link titles
        link.append("title")
            .text(function (d) {
                return d.source.name + " → " +
                    d.target.name + "\n" + format(d.value);
            });

        // add in the nodes
        var node = svg.append("g").selectAll(".node")
            .data(graph.nodes)
            .enter().append("g")
            .attr("class", "node")
            .attr("transform", function (d) {
                return "translate(" + d.x + "," + d.y + ")";
            })
            .call(d3.drag()
                .subject(function (d) {
                    return d;
                })
                .on('start', function (event, d) {
                    this.parentNode.appendChild(this)
                })
                .on("drag", dragmove));

        // add the rectangles for the nodes
        node.append("rect")
            .attr("x", function (d) { return d.x0; })
            .attr("y", function (d) { return d.y0; })
            .attr("height", function (d) { return d.y1 - d.y0; })
            .attr("width", sankey.nodeWidth())
            .style("fill", function (d) {
                return d.color = color(d.name.replace(/ .*/, ""));
            })
            .attr("stroke", "#000")
            .append("title")
            .text(function (d) {
                return d.name + "\n" + format(d.value);
            });

        // add in the title for the nodes
        node.append("text")
            .attr("x", function (d) { return d.x0 - 6; })
            .attr("y", function (d) { return (d.y1 + d.y0) / 2; })
            .attr("dy", "0.35em")
            .attr("text-anchor", "end")
            .text(function (d) { return d.name; })
            .filter(function (d) { return d.x0 < width / 2; })
            .attr("x", function (d) { return d.x1 + 6; })
            .attr("text-anchor", "start");

        // add gradient to links
        link.style('stroke', (d, i) => {
            // make unique gradient ids
            const gradientID = `gradient${i}`;

            const startColor = d.source.color;
            const stopColor = d.target.color;

            console.log('startColor', startColor);
            console.log('stopColor', stopColor);

            const linearGradient = defs.append('linearGradient')
                .attr('id', gradientID);

            linearGradient.selectAll('stop')
                .data([
                    { offset: '25%', color: startColor },
                    { offset: '75%', color: stopColor }
                ])
                .enter().append('stop')
                .attr('offset', d => {
                    console.log('d.offset', d.offset);
                    return d.offset;
                })
                .attr('stop-color', d => {
                    console.log('d.color', d.color);
                    return d.color;
                });

            return `url(#${gradientID})`;
        })
    })

    function dragmove(d) {
        d3.select(this)
            .attr("transform",
                "translate("
                + d.x + ","
                + (d.y = Math.max(
                    0, Math.min(height - d.dy, event.y))
                ) + ")");
        sankey.update(graph);
    }
}

Also, I have an issue when I drag a bar. As you can see in the following screenshot, when I move a bar, it isn't connected with the lines and the bar disappeared.

enter image description here

Enrico
  • 3,592
  • 6
  • 45
  • 102

1 Answers1

2

I know this is a very late reply, but just in case someone else stumbles across on this question, you can use .nodeAlign()

So in the example above:

  "nodes": [
    {
      "group_nodes": 0,
      "name": "CL",
      "id": 0
    },
    {
      "group_nodes": 1,
      "name": "COMT, CL, DA",
      "id": 9
    },
    {
      "group_nodes": 2,
      "name": "COMT",
      "id": 39
    }
  ],
  "links": [
  ]

Using zero indexed groups, you can use:

.nodeAlign((d) => d.group_nodes)
LMox
  • 176
  • 2
  • 5