在d3 sankey图中订购节点

时间:2015-11-01 11:55:15

标签: javascript d3.js

我试图在D3 sankey中订购节点。我希望将值较大的节点绘制得更高。

这是相关代码(based on d3 noob's code)片段,我尝试使用D3的内置排序功能来实现我想要的效果。结果不是我所期望的。

在检查sankey.js时,我并不完全清楚插件是如何命令节点的。任何有关该主题的建议都将受到赞赏。

//set up graph in same style as original example but empty
    graph = {"nodes" : [], "links" : []};

    data.forEach(function (d) {
        graph.nodes.push({ "name": d.source });
        graph.nodes.push({ "name": d.target });
        graph.links.push({ "source": d.source,
            "target": d.target,
            "value": +d.value });
    });

//try to sort the nodes and links before indexing them (not working)
    graph.nodes.sort(function (a,b) {return d3.descending(a.value, b.value); });
    graph.links.sort(function (a,b) {return d3.descending(a.value, b.value); });

    // return only the distinct / unique nodes
    graph.nodes = d3.keys(d3.nest()
        .key(function (d) { return d.name; })
        .map(graph.nodes));

    // loop through each link replacing the text with its index from node
    graph.links.forEach(function (d, i) {
        graph.links[i].source = graph.nodes.indexOf(graph.links[i].source);
        graph.links[i].target = graph.nodes.indexOf(graph.links[i].target);
    });

    //now loop through each nodes to make nodes an array of objects
    // rather than an array of strings
    graph.nodes.forEach(function (d, i) {
        graph.nodes[i] = { "name": d };
    });

4 个答案:

答案 0 :(得分:6)

从sankey.js文件中的resolveCollisions()函数中删除以下行将停止更改节点的顺序:

function resolveCollisions() {
    ...
    // nodes.sort(ascendingDepth);  // commented this out to prevent node reordering
    ...
}

然后,节点将被垂直排序,但它们最初是填充的。因此,如果在推送数据之前先对节点进行排序,它们将按排序顺序显示。

答案 1 :(得分:4)

如果将布局iterations值设置为零,则会按字母顺序(按名称)顺序获取节点:这对我来说效果很好。

var sankey = d3.sankey()
    .nodeWidth(36)
    .nodePadding(40)
    .size([width, height])
    .layout(0);  /* <<<<<<< setting the iterations to zero */

答案 2 :(得分:0)

碰巧遇到了这种情况,它there's an abstraction of d3-sankey(很遗憾)不是很简单的,它允许您设置任意订单(以及其他许多非标准的东西,例如组和周期):

var layout = d3.sankey()
               .extent([[100, 10], [840, 580]]);

var diagram = d3.sankeyDiagram()
                .linkColor(function(d) { return d.color; });

d3.json('uk_energy.json', function(energy) {
  layout.ordering([
      [
        [
          "supply^Indigenous",
          "supply^Imports"
        ],
        [],
        []
      ],
      [
        [
          "primary^Natural gas",
          "primary^Bioenergy & waste",
          "primary^Coal",
          "primary^Manufactured fuel",
          "primary^Primary electricity",
          "primary^Electricity",
          "primary^Petroleum products",
          "primary^Primary oils"
        ],
        [
          "stocks^*"
        ],
        []
      ],
      [
        [
          "transfers^*",
          "transform^Power stns",
          "transform^Other transform",
          "transform^Refineries"
        ],
        [],
        [
          "sink^*"
        ]
      ],
      [
        [
          "secondary^Natural gas",
          "secondary^Bioenergy & waste",
          "secondary^Coal",
          "secondary^Electricity",
          "secondary^Manufactured fuel",
          "secondary^Heat sold",
          "secondary^Petroleum products"
        ],
        [
          "own use^*"
        ],
        [
          "loss^*"
        ]
      ],
      [
        [
          "use1^Other",
          "use1^Industry",
          "use1^Transport"
        ],
        [],
        []
      ],
      [
        [
          "use^Domestic",
          "use^Public administration",
          "use^Commercial",
          "use^Agriculture",
          "use^Miscellaneous",
          "use^Unclassified",
          "use^Iron and steel",
          "use^Non-ferrous metals",
          "use^Mineral products",
          "use^Chemicals",
          "use^Mechanical engineering etc",
          "use^Electrical engineering etc",
          "use^Vehicles",
          "use^Food, beverages etc",
          "use^Textiles, leather etc",
          "use^Paper, printing etc",
          "use^Other industries",
          "use^Construction",
          "use^Air",
          "use^Rail",
          "use^Road",
          "use^National navigation"
        ],
        [],
        []
      ]
    ]
  );
  d3.select('#sankey')
      .datum(layout(energy))
      .call(diagram);
});

根据the docs

  

如果指定了排序,则将节点排序设置为指定的值并返回此布局。如果未指定排序,则返回当前值,默认为null。

     

排序为空时,将自动计算节点排序。

     

指定排序后,将直接使用它,并且不会进行等级分配或排序算法。排序结构具有三个嵌套列表:排序是一个图层列表,每个图层是一个带区列表,每个图层是一个节点ID列表。

AFAICT,示例中的插入符号(^)表示groupName^nodeName

如果您已经深入到一个项目中,这可能没有特别的帮助,但是如果从头开始一个项目,这可能是我的第一个接洽对象。

答案 3 :(得分:0)

以下步骤可用于创建具有自定义节点顺序的sankey。

 let data = {nodes:[],links:[]}
  

订购/排序所有节点的功能

 const sankey = d3.sankey()
    .size(graphSize)
    .nodeId(d => d.id)
    .nodeWidth(nodeWidth)
    .nodePadding(0.5)
    .nodeAlign(nodeAlignment)
    .nodeSort(null) //creates sankey nodes as ordered in the data 

 let graph = sankey(data)

Sankey documentation