D3 Sankey图表使用圆节点代替矩形节点

时间:2014-04-22 00:10:15

标签: javascript svg d3.js transformation sankey-diagram

我想使用Sankey图表,但使用圆圈代替矩形。

我正在关注Mike Bostock中的示例。

我通过设置半径来改变那里的代码以使用圆,但是如何在圆周围放置连接节点的线。

任何线索。

enter image description here

感谢。

1 个答案:

答案 0 :(得分:22)

首先,我想告诉你我喜欢你的主意。

我将向您介绍几个简单的步骤,以获得带圆圈的体面Sankey图表。最终结果可能不适合您的应用程序,但我想这可能对您有用作为起点。一旦你了解了d3 Sankey插件的内部和外部功能,你就应该能够精确地构建你想要的东西。


起点

link to jsfiddle

这只是一个基本的Sankey示例。我在jsfiddle中包含了数据和Sankey插件代码。这只是为了方便,因为jsfidle没有合适的方法来包含多个文件。所以,这是:

enter image description here


第1步

现在我们将做你已经做过的事情 - 将矩形转换为圆圈。

让我们改变这段代码:

// add the rectangles for the nodes
node.append("rect")
    .attr("height", function (d) {
        return d.dy;
    })
    .attr("width", sankey.nodeWidth())

到此代码:

// add the circles for the nodes
node.append("circle")
    .attr("cx", sankey.nodeWidth()/2)
    .attr("cy", function (d) {
        return d.dy/2;
    })
    .attr("r", function (d) {
        return Math.sqrt(d.dy);
    })

我选择使用Math.sqrt(),因为圆圈区域将与它所代表的值成比例。我认为这是圈子最自然的选择。

结果在这里:

enter image description here


第2步

链接现在不自然地宽。让我们改变它们的宽度,使它们与它们所代表的流量的平方根成比例。

让我们改变这段代码:

    .style("stroke-width", function (d) {
        return Math.max(1, d.dy);
    })

到此代码:

    .style("stroke-width", function (d) {
        return Math.max(1, Math.sqrt(d.dy));
    })

结果在这里:

enter image description here


第3步

现在让我们修复链接的端点。

我将使用此answer to another SO question中的代码。

此代码:

var path = sankey.link();

替换为这个:

var path = d3.svg.diagonal()
    .source(function(d) { return {"x":d.source.y, "y":d.source.x}; })            
    .target(function(d) { return {"x":d.target.y, "y":d.target.x}; })
    .projection(function(d) { return [d.y, d.x]; });

结果在这里:

enter image description here


第4步

现在链接节点的链接起点,但是我们需要它们来连接我们圈子的中心

这就是我们改变这段代码的原因:

var path = d3.svg.diagonal()
    .source(function(d) { return {"x":d.source.y, "y":d.source.x}; })            
    .target(function(d) { return {"x":d.target.y, "y":d.target.x}; })
    .projection(function(d) { return [d.y, d.x]; });
    .attr("width", sankey.nodeWidth())

到此代码:

var path = d3.svg.diagonal()
    .source(function(d) {
        return {"x":d.source.y + d.source.dy / 2,
                "y":d.source.x + sankey.nodeWidth()/2};
    })            
    .target(function(d) {
        return {"x":d.target.y + d.target.dy / 2,
                "y":d.target.x + sankey.nodeWidth()/2};
    })
    .projection(function(d) { return [d.y, d.x]; });

结果在这里:

enter image description here

第5步

几乎完成了。在最后一个图中仍然困扰我的是节点标签的位置。如果圆圈较大,则会与其标签重叠。我在最后一个版本中修复了它。结果是:

enter image description here

这是jsfidle of this final step