2012-11-28 2 views
21

Sankey diagram example을 수정하여 새 데이터로 쉽게 전환 할 수 있는지 알고 싶습니다. 예를 들어, 다른 데이터 파일 (energy1.json, energy2.json ...)을 상상해 보면 d3이 첫 번째 데이터 세트의 Sankey 다이어그램을 플로팅 한 다음 대기하고 나중에 두 번째 데이터 세트를 나타내는 상자 배치를 다시 배치 할 수 있습니까?Sankey 다이어그램 전환

+0

혹시이 문제를 해결 했습니까? – PhoebeB

+1

모든 데이터 파일은 노드가 같지만 노드간에 흐름이 다릅니 까? – ASGM

답변

14

가능합니다. 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 함수를 호출하여 레이아웃을 다시 계산하십시오.

  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/

+0

안녕하세요 @ Joe-Jansen이 코드와 함께 jsfiddle입니다. 필요에 따라 포크하고 조정할 수있는 환경이 있으면 매우 유용합니다. – lwall

2

np 최적화 문제 인 연결된 그래프에서 링크 거리를 최소화하려고하는 부분이 노드의 자동 위치 지정을 포함하기 때문에 모든 옵티마이 저는 잠재적으로 하나의 최소 점에서 다른 점으로 이동하여 레이아웃을 점프 할 수 있습니다. 따라서 보장 된 원활한 전환은 불가능합니다.

가능한 가장 가까운 해결책은 두 입력 데이터 집합 사이를 선형 적으로 보간하여 일련의 그래프를 생성하는 것입니다 (데이터에 따라 다름).

희망이 도움이됩니다.

+0

jsfiddle에 예제를 추가해 주실 수 있습니까? 그것은 매우 도움이 될 것입니다! – lwall