首先,我想告诉你我喜欢你的想法。
我将向您介绍几个简单的步骤,以获取带有圆形的不错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));
})
这是结果:
现在让我们修复链接的端点。
我将使用这个另一个SO问题的答案中的代码。
这段代码:
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]; });
结果在这里:
快要完成了。在上一个图中仍然让我担心的是节点标签的位置。如果圆形更大,它将与它的标签重叠。在这个最后版本中,我解决了这个问题。结果如下: