Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

d3.scale.category20b always returning first color

Tags:

d3.js

I try to use d3.scale.category.20b() to generate a color scale, problem is whatever number of the list I ask for, it always returns first element of the list.

var color = d3.scale.category20b();
console.log(color(X));

OR

console.log(d3.scale.category20b()(X);

No matter what X is, it always logs #393b79 which is the first elements, according to the d3 API

like image 296
Aleks G Avatar asked Jul 10 '13 11:07

Aleks G


3 Answers

This can happen because categorical scales in d3 append to the domain as new data comes in. If every enter() creates a new categorical scale, the domain of the categorical scale remains the same.

As an example, please consider this jFiddle: http://jsfiddle.net/seldomawake/MV55j/1/ Here, we see that as data enters, we append to a categorical scale in the global namespace, $colorScale (specific code below).

function redraw(theData) {
    var localColorScale = d3.scale.category20c(); //< NOT USED HERE
    var svg = d3.select("svg");
    var circles = svg.selectAll("circle")
                     .data(theData).enter().append("circle")
     var circleAttributes = circles.attr("cx", getRandomInt(50, 450))
                                   .attr("cy", getRandomInt(50, 450))
                                   .attr("r", function (d) { return d.value; })
                                   .style("fill", function () { return $colorScale(getRandomInt(0, 19)); });
}

However, if we were to replace return $colorScale(getRandomInt(0, 19)) with return localColorScale(getRandomInt(0, 19)), we would no longer have the data append to the range of the categorical scale, and which would result in a single-color output.

Edit: fixing URL to jsfiddle.

like image 116
khan Avatar answered Nov 05 '22 08:11

khan


At first I thought this would have been a bug with D3.js so created this jsfiddle which works fine.

var data = d3.range(0,20);
var color = d3.scale.category20b();

d3.select('.target').selectAll('div')
    .data(data)
    .enter()
        .append('div')
        .text(function(d){return color(d);})
        .attr('style', function(d){return "background-color:"+ color(d) + ";" ;})

It had been raised by others about version of D3 you are using. This looks unlikely to be the cause of your issue as the code in question has hardly been touched. If the code has not been touched much and others have no issue it raises the question of browser compatibly. I sent my jsfiddle to browsershots and did not see any browser output a single block of color instead of the expected pretty color stripes.

After all this it seams there is not enough information to properly answer your problem. I suggest you have a look to see if X is really changing by making a small change to the code console.log({'color':color(X), 'x':X}).

enter image description here

like image 41
Christopher Hackett Avatar answered Nov 05 '22 07:11

Christopher Hackett


Which version of D3 are you using? I wrote a jsFiddle (D3 3.0.4), the colors are shown normally:

var color = d3.scale.category20b();

var svg = d3.select('#chart').append('svg')
    .attr('width', 200)
    .attr('height', 100);

svg.append('rect')
    .attr('width', 100)
    .attr('height', 100)
    .attr('fill', color(0));

svg.append('rect')
    .attr('x', 100)
    .attr('width', 100)
    .attr('height', 100)
    .attr('fill', color(1));

The result is:

Distinct colors

like image 35
Pablo Navarro Avatar answered Nov 05 '22 07:11

Pablo Navarro