简体   繁体   中英

Large data set breaks d3 sankey diagram

I'm making a d3 Sankey diagram from the example in https://bl.ocks.org/d3noob/5028304 . This example works fine with a smaller data set. When I switched to using a larger data set, the visualization breaks. It looks like the problem is that the dy values become negative.

In the console, the error is:

Error: <rect> attribute height: A negative value is not valid. ("-9.02557856272838")

The code it points to is:

node.append("rect")
  .attr("height", function(d) { return d.dy; })

This is perhaps because the plots are going off screen? I looked at using d3 scales, but I'm not sure how to implement them. Maybe something like this:

d3.scale.ordinal()
.domain(data.map(function(d) { return d.name; }))
.rangeRoundBands([0, height], .2);

Or maybe there's a way to shrink the visualization as the data set gets larger so that everything will fit in the container.

Here is my code: https://plnkr.co/edit/hOjEBHhS7vfajD2wb8t9?p=preview

With 945 nodes and 2463 links, there is no way this is going to fit in an 740-pixel-height container. Not only that, you have to ask yourself "how is this dataviz going to be useful to the reader with that huge amount of information?" . But since that's none of my business, you can do a couple of things:

The first one, of course, is filtering your data. If that's not an option, you can increase the container height:

height = 3000 - margin.top - margin.bottom;

And reduce the padding of the nodes:

var sankey = d3.sankey()
    .nodeWidth(36)
    .nodePadding(1)
    .size([width, height]);

The result is in this plunker: https://plnkr.co/edit/Idb6ZROhq1kuZatbGtqg?p=preview

But if even that is not an option, you can change sankey.js code or, in a lazy solution, avoid negative numbers with this:

.attr("height", function(d) { return d.dy < 0 ? 0 : d.y; })

This being the result: https://plnkr.co/edit/tpaMpK5yXwYh9MEo8hgn?p=preview

I've encountered the same problem. I have graphs with 50 nodes and 50 links, but also graphs with 1200 nodes and 1200 links. The first thing I tried was to increase the canvas width and height. So I've increased the width based on the graph depth and the height based on the level where I had the most nodes.

However, I ended up in some edge cases graphs with either a too bigger width or too bigger height. So I ended up with a regeneration of the graph, until each node has a min height and until the space between the linked nodes is reasonable.

So here is what I did:

class SankeyChart {
   sankeyGenerator;
   graph;
   width = 1000;
   height = 1000;

   constructor(private nodes, private links) {
      this.sankeyGenerator = sankey()
        .extent([[10, 10], [this.width - 10, this.height - 10]])
      this.draw();
   }

 
  private draw() {
    this.graph = this.getGraph();
    this.drawLinks(this.graph.links); // method that draw the links
    this.drawNodes(this.graph.nodes); // method that draw the nodes
  }


  private getGraph() {
    const graph = this.sankeyGenerator({nodes: this.nodes, links: this.links});

    const increaseWidth = graph.links.some(l => Math.abs(l.source.y1 - l.target.y0) > 4 * Math.abs(l.source.x1 - l.target.x0));
    const increaseHeight = graph.nodes.some(n => n.y1 - n.y0 < 1);
    if (increaseHeight) {
      this.height += 1000;
    }
    if (increaseWidth) {
      this.width += 1000;
    }
    if (increaseHeight || increaseWidth) {
      this.sankeyGenerator.extent([[10, 10], [this.width - 10, this.height - 10]]);
      return this.getGraph();
    }
    return graph;
  }

}

Note that you might want to perform an extra filter on graph.nodes.some(n => n.y1 - n.y0 < 1); . I had a few cases where all the nodes had y1 - y0 > 1000 , but there were 2 or 3 nodes where y1 - y0 < 0.00000001 .

Also note that you might add a parameter to the class to increase the size of the container more than 1000px each time when getGraph() is called for big charts.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM