答案 0 :(得分:22)
首先,我想告诉你我喜欢你的主意。
我将向您介绍几个简单的步骤,以获得带圆圈的体面Sankey图表。最终结果可能不适合您的应用程序,但我想这可能对您有用作为起点。一旦你了解了d3 Sankey插件的内部和外部功能,你就应该能够精确地构建你想要的东西。
这只是一个基本的Sankey示例。我在jsfiddle中包含了数据和Sankey插件代码。这只是为了方便,因为jsfidle没有合适的方法来包含多个文件。所以,这是:
现在我们将做你已经做过的事情 - 将矩形转换为圆圈。
让我们改变这段代码:
// 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(),因为圆圈区域将与它所代表的值成比例。我认为这是圈子最自然的选择。
结果在这里:
链接现在不自然地宽。让我们改变它们的宽度,使它们与它们所代表的流量的平方根成比例。
让我们改变这段代码:
.style("stroke-width", function (d) {
return Math.max(1, d.dy);
})
到此代码:
.style("stroke-width", function (d) {
return Math.max(1, Math.sqrt(d.dy));
})
结果在这里:
现在让我们修复链接的端点。
我将使用此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]; });
结果在这里:
现在链接节点的链接起点,但是我们需要它们来连接我们圈子的中心
这就是我们改变这段代码的原因:
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]; });
结果在这里:
几乎完成了。在最后一个图中仍然困扰我的是节点标签的位置。如果圆圈较大,则会与其标签重叠。我在最后一个版本中修复了它。结果是: