【问题标题】:Sankey diagram transition桑基图转换
【发布时间】:2012-11-28 11:19:33
【问题描述】:

我想知道是否有一种简单的方法可以修改Sankey diagram example,以便顺利过渡到新数据。例如,假设我有不同的数据文件(energy1.json、energy2.json ...),d3 如何为第一个数据集绘制 Sankey 图,然后等待并稍后重新排列框以表示第二个数据集?

【问题讨论】:

  • 你解决过这个问题吗?
  • 您的所有数据文件是否都具有相同的节点但它们之间的流不同?

标签: json d3.js transition sankey-diagram


【解决方案1】:

这是可能的。这是使用 csv 文件的一种方法。在这里工作 sankey:https://www.betterment.com/resources/investment-strategy/portfolio-management/portfolio-diversification/

  1. 在 d3.csv 调用之外定义一个全局数组。

    var portfolioValues = [];
    
  2. 在解析 csv 以创建节点/链接结构时,将值推送到您的全局数组。

    d3.csv("etf-geo.csv", function(error, data) {
        graph = {"nodes" : [], "links" : []};
        data.forEach(function (d, i) {
            var item = { source: d.source, target: d.target, values: [] };
            for (var j=0; j < 101; j++) {
                item.values.push(d['value'+j.toString()]);
            }
            portfolioValues.push(item);
            graph.nodes.push({ "name": d.source });
            graph.nodes.push({ "name": d.target });
            graph.links.push({
                source: portfolioValues[i].source,
                target: portfolioValues[i].target,
                value: portfolioValues[i].values[startingAllocation]
            });
        });
    
    //this handy little function returns only the distinct / unique nodes
    graph.nodes = d3.keys(
        d3.nest()
            .key(function (d) { return d.name; })
            .map(graph.nodes)
    );
    
    // it appears d3 with force layout wants a numeric source and target
    // so 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);
        portfolioValues[i].source = graph.links[i].source;
        portfolioValues[i].target = 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 };
    });
    
    // construct sankey
    sankey
        .nodes(graph.nodes)
        .links(graph.links)
        .layout();
    
  3. 侦听更改并将用户输入传递给您的更新函数。

    $(".sankey-slider").bind("slider:changed", function (event, data) {
    
    slideValue = data.value;
    
    updateData(parseInt(slideValue));
    
     });
    
  4. 创建一个临时数组并从全局数组中检索正确的值。调用 sankey 函数来重新计算布局。

        var newLinks = [];
    
        portfolioValues.forEach(function(p, i) {
            newLinks.push({
              source: p.source,
              target: p.target,
              value: p.values[allocation]
            });
        });
    
        graph.links = newLinks;
    
        sankey
        .nodes(graph.nodes)
        .links(graph.links)
        .size([width, height])
        .layout();
    
  5. 选择每个需要更改的元素并传递新的数据值。

    d3.selectAll(".link")
      .data(graph.links)
      .attr("d", path)
      .attr("id", function(d,i){
        d.id = i;
        return "link-"+i;
      })
      .style("stroke-width", function(d) { return Math.max(1, d.dy); })
      .sort(function(a, b) { return b.dy - a.dy; });
    
    d3.selectAll(".node").attr("transform", function(d) {
      return "translate(" + d.x + "," + d.y + ")"; });
    
    d3.selectAll("rect")
    .attr("height", function(d) { return d.dy; })
    .on("mouseover",highlight_node_links)
    .on("mouseout",onNodeMouseout);
    

在这里工作的sankey: https://www.betterment.com/resources/investment-strategy/portfolio-management/portfolio-diversification/

【讨论】:

  • 嗨@Joe-Jansen 你的代码有一个jsfiddle。拥有一个可以根据需要进行分叉和调整的环境将非常有用。
【解决方案2】:

由于节点的自动定位包括试图最小化连接图中的链接距离的部分,这是一个 np 优化问题,任何类型的优化器都可能从一个最小值跳转到另一个最小值,从而导致布局跳跃。所以保证平稳过渡是不可能的。

最接近的可能解决方案可能是在两个输入数据集之间进行线性插值,从而生成一系列图表,这些图表(取决于数据)或多或少地从一个两个另一个平滑过渡。

希望这会有所帮助。

【讨论】:

  • 您能在 jsfiddle 上添加一个示例吗?那会很有帮助!
猜你喜欢
  • 2018-02-13
  • 1970-01-01
  • 1970-01-01
  • 2022-10-06
  • 2016-04-06
  • 2010-12-09
  • 2018-07-18
  • 2012-04-15
相关资源
最近更新 更多