2013-07-24 10 views
5

Zrobiłem wykres ukierunkowany na siłę za pomocą wtyczki d3.js i chcę pokolorować węzły i etykiety o innym kolorze w zależności od grupy, do której należą.D3.js wymuszony wykres, każda grupa inny kolor?

Dodałem skalę dla koloru:

var color = d3.scale.category20(); 

i do węzła zmiennej Dodałem:

.style("fill", function(d) { return color(d.group); }) 

ale wszystkie węzły są w tym samym kolorze ..

Tutaj jest moja obecna sytuacja: http://jsfiddle.net/WBkw9/

pełny scenariusz:

var links = [ 
    {source: "John", target: "Mike", group: "5"}, 
    {source: "John", target: "Janice", group: "5"}, 
    {source: "John", target: "Caleb", group: "5"}, 
    {source: "John", target: "Anna", group: "4"}, 
    {source: "John", target: "Tommy", group: "3"}, 
    {source: "John", target: "Jack", group: "2"}, 
    {source: "John", target: "Vilma", group: "1"}, 
]; 

var nodes = {}; 

// Compute the distinct nodes from the links. 
links.forEach(function(link) { 
    link.source = nodes[link.source] || (nodes[link.source] = {name: link.source}); 
    link.target = nodes[link.target] || (nodes[link.target] = {name: link.target}); 
}); 

var color = d3.scale.category20(); 

var width = 960, 
    height = 500; 

var force = d3.layout.force() 
    .nodes(d3.values(nodes)) 
    .links(links) 
    .size([width, height]) 
    .linkDistance(60) 
    .charge(-300) 
    .on("tick", tick) 
    .start(); 

var svg = d3.select("body").append("svg") 
    .attr("width", width) 
    .attr("height", height); 

var link = svg.selectAll(".link") 
    .data(force.links()) 
    .enter().append("line") 
    .attr("class", "link"); 

var node = svg.selectAll(".node") 
    .data(force.nodes()) 
    .enter().append("g") 
    .attr("class", "node") 
    .style("fill", function(d) { return color(d.group); }) 
    .on("mouseover", mouseover) 
    .on("mouseout", mouseout) 
    .call(force.drag); 

node.append("circle") 
    .attr("r", 8); 

node.append("text") 
    .attr("x", 12) 
    .attr("dy", ".35em") 
    .text(function(d) { return d.name; }); 

function tick() { 
    link 
     .attr("x1", function(d) { return d.source.x; }) 
     .attr("y1", function(d) { return d.source.y; }) 
     .attr("x2", function(d) { return d.target.x; }) 
     .attr("y2", function(d) { return d.target.y; }); 

    node 
     .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; }); 
} 

function mouseover() { 
    d3.select(this).select("circle").transition() 
     .duration(750) 
     .attr("r", 16); 
} 

function mouseout() { 
    d3.select(this).select("circle").transition() 
     .duration(750) 
     .attr("r", 8); 
} 

czego brakuje dla różnych kolorów w każdej grupie?

Odpowiedz

3

Twój problem polega na tym, że group nie jest zdefiniowany dla twoich danych. W rezultacie wszystkie twoje węzły są oznaczone kolorem "niezdefiniowana". Twoje kręgi są zdefiniowane dla danych w numerach force.nodes(), które mają atrybuty: index group jest zdefiniowany tylko dla łączy, które nigdy nie mają zastosowanego koloru.

W obecnej postaci nie ma również jasnego sposobu określenia, jaki kolor powinien być węzeł. Co się dzieje, gdy więcej niż jedno łącze łączy się z węzłem, a te łącza znajdują się w różnych grupach?

0

Myślę, że trzeba zmienić atrybut stylu koła, a nie element g.

node.append("circle").style("fill", function(d) { return color(d.group); }) 

Edytuj: Właściwość grupy w danych musi również zostać zmieniona na wartości całkowite lub odłożona później.

+0

to po prostu zmienia kolorystykę w taki sposób, że tylko węzeł jest kolorowy, a nie cały tekst. Ale nadal nie rozwiązuje to mojego problemu, http://jsfiddle.net/F2fbu/. Chcę, aby każda grupa była inna, teraz wydaje mi się, że nie mogę tego zrobić z takimi danymi, ponieważ muszę określić, która grupa jest tym węzłem ... – dzordz

+0

Grupa musi być liczbą całkowitą, a nie łańcuchem. 'd3.selectAll (" circle "). style (" wypełnij ", funkcja (d) {kolor powrotu (9)})" zmienił kolor wszystkich okręgów. – user4815162342

0

Czy kiedykolwiek rozwiązałeś to? Jeżeli nie jest możliwe rozwiązanie jest tutaj: http://jsfiddle.net/adeaver/F2fbu/1/

Każda grupa/węzeł różnych kolorach, wraz z odpowiednim tekście przez dodanie: .style("fill", function(d) { return color(d.group); }) do dołączyć tekst i group: link.group do funkcji, którą oblicza węzły z ogniw

4

Oto mój kod (na podstawie http://bl.ocks.org/mbostock/4062045). Działa idealnie. Możesz zobaczyć, jak to jest tutaj: http://jsfiddle.net/Rom2BE/H2PkT/

Każda grupa ma inny kolor.

**index.html** 

<!DOCTYPE html> 
<meta charset="utf-8"> 
<style> 

.node { 
    stroke: #fff; 
    stroke-width: 1.5px; 
} 

.link { 
    stroke: #999; 
    stroke-opacity: .6; 
} 

</style> 
<body> 
<script src="http://d3js.org/d3.v3.min.js"></script> 
<script> 

var width = 650, 
    height = 700; 

var color = d3.scale.category10(); 

var force = d3.layout.force() 
    .charge(-120) 
    .linkDistance(30) 
    .size([width, height]); 

var svg = d3.select("body").append("svg") 
    .attr("width", width) 
    .attr("height", height); 

d3.json("data.json", function(error, graph) { 
    force 
     .nodes(graph.nodes) 
     .links(graph.links) 
     .start(); 

    var link = svg.selectAll(".link") 
     .data(graph.links) 
    .enter().append("line") 
     .attr("class", "link") 
     .style("stroke-width", function(d) { return Math.sqrt(d.value); }); 

    // You define here your nodes and the color will be d.group 
    var node = svg.selectAll(".node") 
     .data(graph.nodes) 
    .enter().append("circle") 
     .attr("class", "node") 
     .attr("r", 5) 
     .style("fill", function(d) { return color(d.group); }) 
     .call(force.drag); 

    //Display node name when mouse on a node 
    node.append("title") 
     .text(function(d) { return d.name; }); 

    //Where and how nodes are displayed 
    force.on("tick", function() { 
    node.attr("cx", function(d) { return d.x; }) 
     .attr("cy", function(d) { return d.y; }); 

    link.attr("x1", function(d) { return d.source.x; }) 
     .attr("y1", function(d) { return d.source.y; }) 
     .attr("x2", function(d) { return d.target.x; }) 
     .attr("y2", function(d) { return d.target.y; }); 
    }); 

    //Legend 
    var legend = svg.selectAll(".legend") 
     .data(color.domain()) 
    .enter().append("g") 
     .attr("class", "legend") 
     .attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; }); 

    legend.append("rect") 
     .attr("x", width - 18) 
     .attr("width", 18) 
     .attr("height", 18) 
     .style("fill", color); 

    legend.append("text") 
     .attr("x", width - 24) 
     .attr("y", 9) 
     .attr("dy", ".35em") 
     .style("text-anchor", "end") 
     .text(function(d) { return d; }); 
}); 

</script> 


**data.json** 

{"nodes":[ 
    {"name":"Vertex 5","group":"Virtuals-MacBook-Pro-36095"},{"name":"Vertex 9","group":"Virtuals-MacBook-Pro-36095"},{"name":"Vertex 15","group":"Virtuals-MacBook-Pro-3-53688"},{"name":"Vertex 20","group":"Virtuals-MacBook-Pro-36095"},{"name":"Vertex 26","group":"Virtuals-MacBook-Pro-4-40842"},{"name":"Vertex 29","group":"Virtuals-MacBook-Pro-36095"},{"name":"Vertex 33","group":"Virtuals-MacBook-Pro-36095"},{"name":"Vertex 37","group":"Virtuals-MacBook-Pro-36095"},{"name":"Vertex 49","group":"Virtuals-MacBook-Pro-3-53688"},{"name":"Vertex 52","group":"Virtuals-MacBook-Pro-4-40842"},{"name":"Vertex 53","group":"Virtuals-MacBook-Pro-4-40842"},{"name":"Vertex 58","group":"Virtuals-MacBook-Pro-36095"},{"name":"Vertex 59","group":"Virtuals-MacBook-Pro-4-40842"},{"name":"Vertex 65","group":"Virtuals-MacBook-Pro-4-40842"},{"name":"Vertex 73","group":"Virtuals-MacBook-Pro-4-40842"},{"name":"Vertex 74","group":"Virtuals-MacBook-Pro-36095"},{"name":"Vertex 80","group":"Virtuals-MacBook-Pro-36095"},{"name":"Vertex 84","group":"Virtuals-MacBook-Pro-4-40842"},{"name":"Vertex 87","group":"Virtuals-MacBook-Pro-4-40842"},{"name":"Vertex 99","group":"Virtuals-MacBook-Pro-4-40842"} 
], 
"links":[ 
    {"source":5,"value":1,"target":11},{"source":5,"value":1,"target":12},{"source":10,"value":1,"target":12},{"source":11,"value":1,"target":5},{"source":11,"value":1,"target":12},{"source":11,"value":1,"target":14},{"source":12,"value":1,"target":5},{"source":12,"value":1,"target":10},{"source":12,"value":1,"target":11},{"source":14,"value":1,"target":11},{"source":16,"value":1,"target":19},{"source":18,"value":1,"target":19},{"source":19,"value":1,"target":16},{"source":19,"value":1,"target":18} 
]} 
1

Twój informacji grupa jest dostępna tylko w obiekcie links, jak @ckersch już zauważył. Będziesz musiał również dodać informacje o grupie do obiektu nodes. W tym przykładzie, że można zrobić, zmieniając linię 16 do:

link.target = nodes[link.target] || (nodes[link.target] = {name: link.target, group: link.group}); 

ale w przypadku bardziej skomplikowanych danych, z więcej niż jednym source wszystkie źródła miałyby ten sam kolor (lub byłoby to OK?).

Wprowadziłem tę zmianę w tym Fiddle: http://jsfiddle.net/WBkw9/19/.