D3.js: how to decide both the area and the color of each square by the size of each content in treemap?

StackOverflow https://stackoverflow.com/questions/21734017

Question

I met a problem in treemap. I have an example much like this: https://secure.polisci.ohio-state.edu/faq/d3/zoomabletreemap.htm

You can see from the demo, the area of each square in the treemap is decided by the content size. While, each square has the same color. So I plan to add the feature: add different shades to each square, which can also be decided by the content size. And also, you can try and fix in this link:

http://jsfiddle.net/srvikram13/cR35x/9/

My solution is binding the color coding style of each square with the each size, then they can show different shades, just like

`.style("background-color", function(size) { return rgb() or something......})`

Thanks in advance!

Was it helpful?

Solution

To just focus on your original question, how to make fill colours dependent on the data:

What you want is a function to convert a numerical data value (the value associated with the size of your treemap rectangles) into a colour value, in such a way that colours form a smooth transition between two extremes representing the extremes of the data.

The ordinal colour scales don't do this, they're intended to create distinct colour values for contrast.

To create a linear relationship to the data, you'll need a linear scale to convert the data values into an appropriate range for the colour functions, and then you'll need a function to create the actual colour value that varies according to that number.

There are three sets of functions within d3 that create variations on colour:

  • The colour interpolator functions, which are used internally when you specify a transition for a colour property, are initialized with a start colour and an end colour, and return a function that will take values between 0 and 1 and return a colour the appropriate distance between the start and end values.

  • The create colour functions take three numbers as either a RGB, HSL, or L*a*b colour definition, and return the hex value; you can specify any of these numbers with a linear scale to create a scale of colours that vary only one that one dimension (hue, lightness, redness, whatever).

  • The brighter/darker colour functions, which are initialized with one colour value and then can be used to create modifications of it. However, they can only modify the brightness, not the hue.

The colour interpolator functions are much more flexible, so that's what I'd recommend using. There are different versions depending on whether you want the interpolation to vary according to RGB colour space or HSL or L*a*b colour space. I'd recommend using HSL for intuitive transitions that won't ever stray outside of visible colours.

Again, the interpolator function will expect a value between 0 and 1, so you'll need to use a linear scale to convert your data values to that range.

var colourScale = d3.scale.linear()
                    .domain([0, maxArea])
                    .range([0,1]);
var colourInterpolator = d3.interpolateHsl("blue", "red") 
               //colours can be specified as any CSS colour string

function colourFunction(d) {
    return colourInterpolator( colourScale( d.area ) );
}

/* and then later */
rect.attr("fill", colourFunction);

If the rectangle's area is equal to the maximum, the scale will convert that to a value of 1, and the colour interpolator will convert that to the final colour of the transition, red. If the area is almost zero, the scale value will be almost zero, and the colour will be almost blue.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top