D3桑基图使用圆形节点而不是矩形节点

11

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

我正在遵循 Mike Bostock 的示例。

我已经通过设置半径来更改了代码以使用圆,但如何在圆周围放置连接节点的线条。

有什么提示吗。

enter image description here

谢谢。


分享你的代码将使其他人更容易帮助你。 - MasterAM
1个回答

26

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

我将向您介绍几个简单的步骤,以获取带有圆形的不错Sankey图。最终结果可能不是您的应用理想的,但我认为它可以作为起点对您有用。一旦您了解了d3 Sankey插件的内部和外部特性,您应该能够精确地构建您所设计和希望的内容。


起点

jsfiddle链接

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

输入图像描述


第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(),因为这样圆的面积将与它所代表的值成比例。我认为这是圆形最自然的选择。

结果在这里:

输入图像描述


第二步

链接现在过于宽了。让我们将它们的宽度改为与它们所代表的流量的平方根成比例。

让我们更改这段代码:

    .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


第三步

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

我将使用这个另一个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]; });

这是结果:

enter image description here


第四步

现在链接连接的是节点的起点和终点,但我们需要它们连接圆心。

这就是为什么我们要更改这段代码:

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


1
非常好的解释。这正是我在寻找的内容。非常感谢。 - user2300875
非常感谢。完美的答案! - Melki
解释非常清晰,非常感谢!只是在您进行节点大小缩小时有一个小故障:dragmove仍然按照原始节点大小(即约束)行为。特别是在node7上。我尝试了一些方法但没有成功。您对此有什么想法吗? - Sbu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接