2016-02-29 171 views
1

我是新來D3 JS和試圖顯示百分比由節點的熱平衡圖上。我可以在sankey中顯示百分比,但它會按總價值計算百分比。任何幫助表示讚賞。 謝謝!顯示百分比使用D3 JS

d3.sankey = function() { 
 
    var sankey = {}, 
 
     nodeWidth = 24, 
 
     nodePadding = 8, 
 
     size = [1, 1], 
 
     nodes = [], 
 
     links = []; 
 

 
    sankey.nodeWidth = function(_) { 
 
    if (!arguments.length) return nodeWidth; 
 
    nodeWidth = +_; 
 
    return sankey; 
 
    }; 
 

 
    sankey.nodePadding = function(_) { 
 
    if (!arguments.length) return nodePadding; 
 
    nodePadding = +_; 
 
    return sankey; 
 
    }; 
 

 
    sankey.nodes = function(_) { 
 
    if (!arguments.length) return nodes; 
 
    nodes = _; 
 
    return sankey; 
 
    }; 
 

 
    sankey.links = function(_) { 
 
    if (!arguments.length) return links; 
 
    links = _; 
 
    return sankey; 
 
    }; 
 

 
    sankey.size = function(_) { 
 
    if (!arguments.length) return size; 
 
    size = _; 
 
    return sankey; 
 
    }; 
 

 
    sankey.layout = function(iterations) { 
 
    computeNodeLinks(); 
 
    computeNodeValues(); 
 
    computeNodeBreadths(); 
 
    computeNodeDepths(iterations); 
 
    computeLinkDepths(); 
 
    return sankey; 
 
    }; 
 

 
    sankey.relayout = function() { 
 
    computeLinkDepths(); 
 
    return sankey; 
 
    }; 
 

 
    sankey.link = function() { 
 
    var curvature = .5; 
 

 
    function link(d) { 
 
     var x0 = d.source.x + d.source.dx, 
 
      x1 = d.target.x, 
 
      xi = d3.interpolateNumber(x0, x1), 
 
      x2 = xi(curvature), 
 
      x3 = xi(1 - curvature), 
 
      y0 = d.source.y + d.sy + d.dy/2, 
 
      y1 = d.target.y + d.ty + d.dy/2; 
 
     return "M" + x0 + "," + y0 
 
      + "C" + x2 + "," + y0 
 
      + " " + x3 + "," + y1 
 
      + " " + x1 + "," + y1; 
 
    } 
 

 
    link.curvature = function(_) { 
 
     if (!arguments.length) return curvature; 
 
     curvature = +_; 
 
     return link; 
 
    }; 
 

 
    return link; 
 
    }; 
 

 
    // Populate the sourceLinks and targetLinks for each node. 
 
    // Also, if the source and target are not objects, assume they are indices. 
 
    function computeNodeLinks() { 
 
    nodes.forEach(function(node) { 
 
     node.sourceLinks = []; 
 
     node.targetLinks = []; 
 
    }); 
 
    links.forEach(function(link) { 
 
     var source = link.source, 
 
      target = link.target; 
 
     if (typeof source === "number") source = link.source = nodes[link.source]; 
 
     if (typeof target === "number") target = link.target = nodes[link.target]; 
 
     source.sourceLinks.push(link); 
 
     target.targetLinks.push(link); 
 
    }); 
 
    } 
 

 
    // Compute the value (size) of each node by summing the associated links. 
 
    function computeNodeValues() { 
 
    nodes.forEach(function(node) { 
 
     node.value = Math.max(
 
     d3.sum(node.sourceLinks, value), 
 
     d3.sum(node.targetLinks, value) 
 
    ); 
 
    }); 
 
    } 
 

 
    // Iteratively assign the breadth (x-position) for each node. 
 
    // Nodes are assigned the maximum breadth of incoming neighbors plus one; 
 
    // nodes with no incoming links are assigned breadth zero, while 
 
    // nodes with no outgoing links are assigned the maximum breadth. 
 
    function computeNodeBreadths() { 
 
    var remainingNodes = nodes, 
 
     nextNodes, 
 
     x = 0; 
 

 
    while (remainingNodes.length) { 
 
     nextNodes = []; 
 
     remainingNodes.forEach(function(node) { 
 
     node.x = x; 
 
     node.dx = nodeWidth; 
 
     node.sourceLinks.forEach(function(link) { 
 
      nextNodes.push(link.target); 
 
     }); 
 
     }); 
 
     remainingNodes = nextNodes; 
 
     ++x; 
 
    } 
 

 
    // 
 
    moveSinksRight(x); 
 
    scaleNodeBreadths((width - nodeWidth)/(x - 1)); 
 
    } 
 

 
    function moveSourcesRight() { 
 
    nodes.forEach(function(node) { 
 
     if (!node.targetLinks.length) { 
 
     node.x = d3.min(node.sourceLinks, function(d) { return d.target.x; }) - 1; 
 
     } 
 
    }); 
 
    } 
 

 
    function moveSinksRight(x) { 
 
    nodes.forEach(function(node) { 
 
     if (!node.sourceLinks.length) { 
 
     node.x = x - 1; 
 
     } 
 
    }); 
 
    } 
 

 
    function scaleNodeBreadths(kx) { 
 
    nodes.forEach(function(node) { 
 
     node.x *= kx; 
 
    }); 
 
    } 
 

 
    function computeNodeDepths(iterations) { 
 
    var nodesByBreadth = d3.nest() 
 
     .key(function(d) { return d.x; }) 
 
     .sortKeys(d3.ascending) 
 
     .entries(nodes) 
 
     .map(function(d) { return d.values; }); 
 

 
    // 
 
    initializeNodeDepth(); 
 
    resolveCollisions(); 
 
    for (var alpha = 1; iterations > 0; --iterations) { 
 
     relaxRightToLeft(alpha *= .99); 
 
     resolveCollisions(); 
 
     relaxLeftToRight(alpha); 
 
     resolveCollisions(); 
 
    } 
 

 
    function initializeNodeDepth() { 
 
     var ky = d3.min(nodesByBreadth, function(nodes) { 
 
     return (size[1] - (nodes.length - 1) * nodePadding)/d3.sum(nodes, value); 
 
     }); 
 

 
     nodesByBreadth.forEach(function(nodes) { 
 
     nodes.forEach(function(node, i) { 
 
      node.y = i; 
 
      node.dy = node.value * ky; 
 
     }); 
 
     }); 
 

 
     links.forEach(function(link) { 
 
     link.dy = link.value * ky; 
 
     }); 
 
    } 
 

 
    function relaxLeftToRight(alpha) { 
 
     nodesByBreadth.forEach(function(nodes, breadth) { 
 
     nodes.forEach(function(node) { 
 
      if (node.targetLinks.length) { 
 
      var y = d3.sum(node.targetLinks, weightedSource)/d3.sum(node.targetLinks, value); 
 
      node.y += (y - center(node)) * alpha; 
 
      } 
 
     }); 
 
     }); 
 

 
     function weightedSource(link) { 
 
     return center(link.source) * link.value; 
 
     } 
 
    } 
 

 
    function relaxRightToLeft(alpha) { 
 
     nodesByBreadth.slice().reverse().forEach(function(nodes) { 
 
     nodes.forEach(function(node) { 
 
      if (node.sourceLinks.length) { 
 
      var y = d3.sum(node.sourceLinks, weightedTarget)/d3.sum(node.sourceLinks, value); 
 
      node.y += (y - center(node)) * alpha; 
 
      } 
 
     }); 
 
     }); 
 

 
     function weightedTarget(link) { 
 
     return center(link.target) * link.value; 
 
     } 
 
    } 
 

 
    function resolveCollisions() { 
 
     nodesByBreadth.forEach(function(nodes) { 
 
     var node, 
 
      dy, 
 
      y0 = 0, 
 
      n = nodes.length, 
 
      i; 
 

 
     // Push any overlapping nodes down. 
 
     nodes.sort(ascendingDepth); 
 
     for (i = 0; i < n; ++i) { 
 
      node = nodes[i]; 
 
      dy = y0 - node.y; 
 
      if (dy > 0) node.y += dy; 
 
      y0 = node.y + node.dy + nodePadding; 
 
     } 
 

 
     // If the bottommost node goes outside the bounds, push it back up. 
 
     dy = y0 - nodePadding - size[1]; 
 
     if (dy > 0) { 
 
      y0 = node.y -= dy; 
 

 
      // Push any overlapping nodes back up. 
 
      for (i = n - 2; i >= 0; --i) { 
 
      node = nodes[i]; 
 
      dy = node.y + node.dy + nodePadding - y0; 
 
      if (dy > 0) node.y -= dy; 
 
      y0 = node.y; 
 
      } 
 
     } 
 
     }); 
 
    } 
 

 
    function ascendingDepth(a, b) { 
 
     return a.y - b.y; 
 
    } 
 
    } 
 

 
    
 
    function computeLinkDepths() { 
 
    nodes.forEach(function(node) { 
 
     node.sourceLinks.sort(ascendingTargetDepth); 
 
     node.targetLinks.sort(ascendingSourceDepth); 
 
    }); 
 
    nodes.forEach(function(node) { 
 
     var sy = 0, ty = 0; 
 
     node.sourceLinks.forEach(function(link) { 
 
     link.sy = sy; 
 
     sy += link.dy; 
 
     }); 
 
     node.targetLinks.forEach(function(link) { 
 
     link.ty = ty; 
 
     ty += link.dy; 
 
     }); 
 
    }); 
 

 
    function ascendingSourceDepth(a, b) { 
 
     return a.source.y - b.source.y; 
 
    } 
 

 
    function ascendingTargetDepth(a, b) { 
 
     return a.target.y - b.target.y; 
 
    } 
 
    } 
 

 
    function center(node) { 
 
    return node.y + node.dy/2; 
 
    } 
 

 
    function value(link) { 
 
    return link.value; 
 
    } 
 

 
    return sankey; 
 
};
<!DOCTYPE html> 
 
<meta charset="utf-8"> 
 
<title>SANKEY Experiment</title> 
 
<style> 
 
.node rect { 
 
    cursor: move; 
 
    fill-opacity: .9; 
 
    shape-rendering: crispEdges; 
 
} 
 
.node text { 
 
    pointer-events: none; 
 
    text-shadow: 0 1px 0 #fff; 
 
} 
 
.link { 
 
    fill: none; 
 
    stroke: #000; 
 
    stroke-opacity: .2; 
 
} 
 
.link:hover { 
 
    stroke-opacity: .5; 
 
} 
 
</style> 
 
<Head> 
 
<link rel="stylesheet" type="text/css" href="sankey.css"> 
 
<h1> 
 
<div class="container"> 
 
    <div>Equipment</div><div>Resolution</div><div>Repeat_call_Flag</div> 
 
</div> 
 
</h1> 
 
</Head> 
 
<body> 
 

 

 
<p id="chart"> 
 

 
<script src="http://d3js.org/d3.v3.min.js"></script> 
 
<script src="sankey.js"></script> 
 
<script> 
 
\t 
 
var units = "Widgets"; 
 
var margin = {top: 10, right: 10, bottom: 10, left: 10}, 
 
    width = 1800 - margin.left - margin.right, 
 
    height = 1300 - margin.top - margin.bottom; 
 
var formatNumber = d3.format(",.0f"), // zero decimal places 
 
    format = function(d) { return formatNumber(d) + " " + units; }, 
 
    color = d3.scale.category20(); 
 
// append the svg canvas to the page 
 
var svg = d3.select("#chart").append("svg") 
 
    .attr("width", width + margin.left + margin.right) 
 
    .attr("height", height + margin.top + margin.bottom) 
 
    .append("g") 
 
    .attr("transform", 
 
      "translate(" + margin.left + "," + margin.top + ")"); 
 
// Set the sankey diagram properties 
 
var sankey = d3.sankey() 
 
    .nodeWidth(20) 
 
    .nodePadding(30) 
 
    .size([width, height]); 
 
var path = sankey.link(); 
 
// load the data (using the timelyportfolio csv method) 
 
d3.csv("sankey.csv", function(error, data) { 
 
    //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 }); \t \t \t \t \t \t \t \t \t \t \t // changed the name here 
 
     graph.links.push({ "source": d.source, 
 
         "target": d.target, 
 
         "value": +d.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 }; 
 
    }); 
 
    sankey 
 
    .nodes(graph.nodes) 
 
    .links(graph.links) 
 
    .layout(50); 
 
// add in the links 
 
    var link = svg.append("g").selectAll(".link") 
 
     .data(graph.links) 
 
    .enter() 
 
\t .append("path") 
 
     .attr("class", "link") 
 
\t .attr("id",function(d,i) { return "linkLabel" + i; }) 
 
     .attr("d", path) 
 
     .style("stroke-width", function(d) { 
 
\t return Math.max(1, d.dy); }) 
 
     .sort(function(a, b) { return b.dy - a.dy; }); 
 

 
// % calculation \t 
 
    var total = d3.sum(data, function(d) {return d.value}); \t  \t \t \t \t // % data label experiment 
 
    var toPercent = d3.format("0.1%") 
 
    
 
    //show travel points \t \t 
 
    /*var labelText = svg.selectAll(".labelText") 
 
    .data(graph.links) 
 
    .enter() 
 
    .append("text") 
 
    .attr("class","labelText") 
 
    .attr("dx",130) 
 
    .attr("dy",0) 
 
    .append("textPath") 
 
    .attr("xlink:href",function(d,i) { return "#linkLabel" + i;}) 
 
    .text(function(d,i) {         
 
\t return d.source.name + " → " + d.target.name + " : " + d.value;})*/ 
 
/* \t  
 
// add the link titles 
 
    link.append("title") 
 
     .text(function(d) { 
 
    \t \t return d.source.name + " → " + 
 
       d.target.name + "\n" + format(d.value); }); */ 
 

 
\t \t \t \t 
 
// add in the nodes 
 
    var node = svg.append("g").selectAll(".node") 
 
     .data(graph.nodes) 
 
    .enter().append("g") 
 
     .attr("class", "node") 
 
     .attr("transform", function(d) { 
 
\t \t return "translate(" + d.x + "," + d.y + ")"; }) 
 
    .call(d3.behavior.drag() 
 
     .origin(function(d) { return d; }) 
 
     .on("dragstart", function() { 
 
\t \t this.parentNode.appendChild(this); }) 
 
     .on("drag", dragmove)); 
 
// add the rectangles for the nodes 
 
    node.append("rect") 
 
     .attr("height", function(d) { return d.dy; }) 
 
     .attr("width", sankey.nodeWidth()) 
 
     .style("fill", function(d) { 
 
\t \t return d.color = color(d.name.replace(/ .*/, "")); }) 
 
     .style("stroke", function(d) { 
 
\t \t return d3.rgb(d.color).darker(2); }) 
 
    .append("title") 
 
     .text(function(d) { 
 
\t \t return d.name + "\n" + format(d.value); }); 
 
// add in the title for the nodes 
 
node.append("text") 
 
     .attr("x", -6) 
 
     .attr("y", function(d) { return d.dy/2; }) 
 
     .attr("dy", ".35em") 
 
     .attr("text-anchor", "end") 
 
     .attr("transform", null) 
 
     .text(function(d) { return d.name + " : " + d.value + " : " + toPercent(d.value/total); }) \t \t \t \t \t //added d.value and % 
 
     .filter(function(d) { return d.x < width/2; }) 
 
     .attr("x", 6 + sankey.nodeWidth()) 
 
     .attr("text-anchor", "start"); 
 
// the function for moving the nodes 
 
    function dragmove(d) { 
 
    d3.select(this).attr("transform", 
 
     "translate(" + d.x + "," + (
 
       d.y = Math.max(0, Math.min(height - d.dy, d3.event.y)) 
 
      ) + ")"); 
 
    sankey.relayout(); 
 
    link.attr("d", path); 
 
    } 
 
    
 

 
}); 
 
</script> 
 

 
</body> 
 
</html>

+0

我不清楚你想要做什麼和不CSV和CSS文件我不能複製你的代碼。也許你可以建立一個jsfiddle.net來演示。加上你的標籤看起來像他們在錯誤的位置,他們應該是小寫。 – emma

回答

1

如果我理解正確的,你要計算的任何節點值的比例超過一定total,使每列和100%。

您需要計算total只考慮源節點(那些不是任何鏈接的目標),這應該給你想要的總數。這一個替換當前的公式total

var total = d3.sum(graph.nodes, function(d) { 
    if (d.targetLinks.length>0) 
     return 0; //node is not source, exclude it from the total 
    else 
     return d.value; //node is a source: add its value to the sum 
    });  

很難說更不需要一個運行的例子或你想要什麼清晰的概念。

+0

工作,謝謝! – user87742