Nima Akram
Nima Akram

Reputation: 58

How to assign consistent colours to node groups in Force Network d3.js

I am trying to assign a specific colour to a specific group in my force network graph. This is so that the groups are assigned the same colours consistently across all my graphs. The group names are "a", "b", "c", "d" and they are assigned a colour in accordance to their order currently.

What I want, for example, is "a" to consistently be assigned to Blue and "b" always to Red.

The JavaScript I have for the node colouring is below:

var color = d3.scale.category10();

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

Any help would be much appreciated,

Thank you

Upvotes: 1

Views: 851

Answers (1)

Gerardo Furtado
Gerardo Furtado

Reputation: 102194

d3.scale.category10() (or d3.schemeCategory10 in v4) works on a first-come, first-served basis. It means that, if you don't set a domain,

the domain will be inferred implicitly from usage by assigning each unique value passed to the scale a new value from the range. (source)

We can easily show this. Have a look at this demo, where I'm using two color scales:

var data = ["a", "b", "c", "d"];
var color = d3.scale.category10();
var color2 = d3.scale.category10();
var body = d3.select("body")

var paragraphs1 = body.selectAll(null)
  .data(data)
  .enter()
  .append("p")
  .style("background-color", function(d) {
    return color(d)
  })
  .html(String);

body.append("br");

var paragraphs1 = body.selectAll(null)
  .data(data.reverse())
  .enter()
  .append("p")
  .style("background-color", function(d) {
    return color2(d)
  })
  .html(String);
p {
  margin: 0px;
}
<script src="https://d3js.org/d3.v3.min.js"></script>

As you can see, the data itself doesn't matter, just the order.

To have a color consistently assigned to a datum value, as you asked, we just need to set the domain:

var color = d3.scale.category10()
    .domain(["a", "b", "c", "d"]);

Here is the demo, now the colors are the same for the same datum:

var data = ["a", "b", "c", "d"];
var color = d3.scale.category10()
  .domain(data);
var color2 = d3.scale.category10()
  .domain(data);
var body = d3.select("body")

var paragraphs1 = body.selectAll(null)
  .data(data)
  .enter()
  .append("p")
  .style("background-color", function(d) {
    return color(d)
  })
  .html(String);

body.append("br");

var paragraphs1 = body.selectAll(null)
  .data(data.reverse())
  .enter()
  .append("p")
  .style("background-color", function(d) {
    return color2(d)
  })
  .html(String);
p {
  margin: 0px;
}
<script src="https://d3js.org/d3.v3.min.js"></script>

Upvotes: 4

Related Questions