2014-11-25 12 views
8

Vorrei forzare un ramo del diagramma di sankey in cima.Come forzare la posizione di un ramo nel plugin sankey d3?

Invece di schema come questo: Current diagram

vorrebbe generare diagramma in cui i nodi 1, 2, 7, 15, 10 e 14 sono sempre in primo piano: Modified diagram

link a giocherellare con corrente codice: http://jsfiddle.net/w5jfp9t0/1/

var margin = {top: 1, right: 1, bottom: 6, left: 1}; 
var width = 1052 - margin.left - margin.right; 
var height = 500 - margin.top - margin.bottom; 

var formatNumber = d3.format(",.0f"), 
    format = function(d) { return formatNumber(d); }, 
    color = d3.scale.category20(); 

var svg = d3.select("#chart_sankey").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 + ")"); 

var sankey = d3.sankey() 
         .nodeWidth(35) 
         .nodePadding(10) 
         .size([width, height]); 

var path = sankey.link(); 

raw = '{"nodes":[{"name":"Node 1"},{"name":"Node 2"},{"name":"Node 3"},{"name":"Node 4"},{"name":"Node 5"},{"name":"Node 6"},{"name":"Node 7"},{"name":"Node 8"},{"name":"Node 9"},{"name":"Node 10"},{"name":"Node 11"},{"name":"Node 12"},{"name":"Node 13"},{"name":"Node 14"},{"name":"Node 15"}],"links":[{"source":9,"target":13,"value":25},{"source":14,"target":9,"value":37},{"source":14,"target":11,"value":16},{"source":14,"target":12,"value":8},{"source":14,"target":10,"value":68},{"source":6,"target":14,"value":154},{"source":6,"target":8,"value":40},{"source":1,"target":6,"value":345},{"source":1,"target":7,"value":66},{"source":1,"target":3,"value":17},{"source":1,"target":4,"value":25},{"source":1,"target":5,"value":117},{"source":0,"target":1,"value":692},{"source":0,"target":2,"value":19}]}'; 
data = JSON.parse(raw); 

sankey.nodes(data.nodes) 
    .links(data.links) 
    .layout(32); 

var link = svg.append("g") 
      .selectAll(".link") 
      .data(data.links) 
      .enter().append("path") 
      .attr("class", "link") 
      .attr("d", path) 
      .style("stroke-width", function(d) { return Math.max(1, d.dy); }) 
      .sort(function(a, b) { return b.dy - a.dy; }); 

var nodes = data.nodes; 

var node = svg.append("g").selectAll(".node") 
    .data(nodes) 
    .enter().append("g") 
    .attr("class", "node") 
    .attr("transform", function(d) { 
     return "translate(" + d.x + "," + d.y + ")"; }) 
    .call(d3.behavior.drag() 
    .origin(function(d) { return d; }) 
    .on("dragstart", function() { this.parentNode.appendChild(this); }) 
    .on("drag", dragmove)); 

sankey.relayout(); 

node.filter(function(d) { return d.value != 0; }) // append text only if node value is not zero 
    .append("rect") 
    .attr("height", function(d) { return d.dy; }) 
    .attr("width", sankey.nodeWidth()) 
    .style("fill", function(d) { return d.color = color(d.name.replace(/ .*/, "")); }) 
    .style("stroke", function(d) { return d3.rgb(d.color).darker(2); }) 
    .append("title") 
    .text(function(d) { return d.name + "\n" + format(d.value); }); 

node.filter(function(d) { return d.value != 0; }) // append text only if node value is not zero 
    .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; }) 
    .filter(function(d) { return d.x == 0; }) // at first column append text after column 
    .attr("x", 6 + sankey.nodeWidth()) 
    .attr("text-anchor", "start"); 

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); 
} 

di cosa ho bisogno di cambiare per raggiungere questo obiettivo?

risposta

10

Nota A dire il vero, non ho mai usato quel plug-in. Non vedo un'opzione per ottenere direttamente il comportamento desiderato, quindi ho cercato la fonte di sankey.js per apportare le modifiche. Qui di seguito vi mostro come avrei modifico - si potrebbe desiderare di farlo :) più a fondo

Idea

Guardando il codice di sankey.js, si vede che i nodi vengono posizionati (direzione y) utilizzando la funzione di center:

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

Come io non vedo un parametro per modificare l'azione, è possibile modificarla in:

function center(node) { 
    return 0; 
} 

Se poi anche ripristinare l'ordinamento:

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

si ottiene la seguente immagine:

enter image description here

+0

Funziona come un fascino! Grazie! Spero di riuscire a capire come spostare anche il nodo 14 :). – tomazzlender

+2

Non essere troppo veloce per accettare :) forse altre persone hanno approcci diversi. Inoltre, potresti voler giocare con la funzione di ordinamento (magari basandola su qualche altro attributo) per ottenere altri effetti. In bocca al lupo! (Ho mantenuto la mia risposta "open ended" volutamente :)) –

+0

La tua soluzione è abbastanza buona per il momento, ma hai ragione che altri potrebbero contribuire con soluzioni diverse. :) – tomazzlender