简体   繁体   English

大数据集打破 d3 桑基图

[英]Large data set breaks d3 sankey diagram

I'm making a d3 Sankey diagram from the example in https://bl.ocks.org/d3noob/5028304 .我正在从https://bl.ocks.org/d3noob/5028304 中的示例制作 d3 Sankey 图。 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.看起来问题在于 dy 值变为负数。

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.我查看了使用 d3 比例,但我不确定如何实现它们。 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这是我的代码: 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.有 945 个节点和 2463 个链接,这不可能适合 740 像素高的容器。 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结果在这个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:但是,即使这不是一个选项,您也可以更改sankey.js代码,或者在懒惰的解决方案中,避免使用负数:

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

This being the result: https://plnkr.co/edit/tpaMpK5yXwYh9MEo8hgn?p=preview结果如下: 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.我有包含 50 个节点和 50 个链接的图表,但也有包含 1200 个节点和 1200 个链接的图表。 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);请注意,您可能希望对graph.nodes.some(n => n.y1 - n.y0 < 1);执行额外的过滤器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 .我有一些情况,所有节点的y1 - y0 > 1000 ,但有 2 或 3 个节点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.另请注意,每次为大图表调用getGraph()时,您可能会向类添加一个参数以将容器的大小增加 1000 像素以上。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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