Alex KeySmith
Alex KeySmith

Reputation: 17091

d3 color scale - linear with multiple colors?

I'm trying to create something a little like a quantize scale, but act like a linear color scale?

When I try to put multiple colors into a linear scale, it seems to only scale between the first two colors.

I'd like multiple colors like a quantize scale, but fade between those colors. I'm unsure if this is possible.

//red and green works ok
var color = d3.scale.linear()
            .range(['red','green']);

//doesn't work - only red and green show
var color = d3.scale.linear()
            .range(['red','green', 'blue']);


//red green and blue show, however it doesn't fade between the colors
var color = d3.scale.quantize()
            .range(['red','green', 'blue']);

Upvotes: 24

Views: 34609

Answers (2)

Peter
Peter

Reputation: 1260

Anto's solution works great if you want to blend 3 colors. In my case, I needed a way to blend an arbitrary number of colors. For me, the trick was to set up the domain correctly. Take for example, the following array of colors:

var colors = ['#084594', '#2171b5', '#4292c6', '#6baed6', '#9ecae1', '#c6dbef', '#eff3ff'];

You can create a domain array with values from -1 to +1 like this:

    var domain = [-1];
    var increment = 2/(colors.length-1);
    for (var i=0; i<colors.length-2; i++){
        var previous = domain[domain.length-1];
        domain.push(previous+increment);
    }
    domain.push(1);

Once the domain array is created, you can create a color function like this:

    var getColor = d3.scaleLinear()
        .domain(domain)
        .range(colors);

If you want to get color values at specific percentages (like chroma does), you can do something like this:

    var p = 0.25; //Valid range for p is 0.0-1.0
    var x = (p*2)-1;
    var color = d3.color(getColor(x));
    console.log(color.formatHex());

Upvotes: 0

Anto Jurković
Anto Jurković

Reputation: 11258

You have to use domain 'pivot' value like:

d3.scale.linear()
    .domain([0, pivot, max])
    .range(['red', 'green', 'blue']);

From the documentation for continuous scale domains:

Although continuous scales typically have two values each in their domain and range, specifying more than two values produces a piecewise scale. For example, to create a diverging color scale that interpolates between white and red for negative values, and white and green for positive values, say:

var color = d3.scaleLinear()
    .domain([-1, 0, 1])
    .range(["red", "white", "green"]);

color(-0.5); // "rgb(255, 128, 128)"
color(+0.5); // "rgb(128, 192, 128)"

Upvotes: 37

Related Questions