Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

D3: Create a continuous color scale with many strings/inputs for the range and dynamically changing values of the domain

Tags:

I am trying to create a linear color scale for a heatmap. I want to color scale to go through a large set of specific colors, where the first color corresponds to the min of the data and the last color should be given to the max of the data.

I know that I can do this by also giving the domain 17 values in between the min and max, but I do not know how to do this dynamically if the user is able to change the dataset (and thus change the coloring of the heatmap)

In essence I would like to following, but I know it does not work

var colorScale = d3.scale.linear()    .range(["#6363FF", "#6373FF", "#63A3FF", "#63E3FF", "#63FFFB", "#63FFCB",            "#63FF9B", "#63FF6B", "#7BFF63", "#BBFF63", "#DBFF63", "#FBFF63",             "#FFD363", "#FFB363", "#FF8363", "#FF7363", "#FF6364"])    .domain([d3.min(dataset, function(d) {return d;}),             d3.max(dataset, function(d) {return d;})]); 

Can anybody please tell me what I need to put into 'domain' to make it work?

EDIT: I did find something that does what I want. Using R I calculated 256 colors in between the 17 from above with the designer.colors functions and put this into the range. This does give the feeling of a continous color scale

var colorScale = d3.scale.linear()     .range(["#6363FF", "#6364FF", "#6364FF", "#6365FF",             "... several other lines with color codes ..."             "#FF6764", "#FF6564", "#FF6464", "#FF6364"])     .domain(d3.range(1,257));  var quantize = d3.scale.quantile()    .range(d3.range(1,257))    .domain([d3.min(dataset, function(d) {return d;}),              d3.max(dataset, function(d) {return d;})]); 

Now I can use the color in this fashion

colorScale(quantize(dataset)) 

But I'm wondering if this can also be done in less lines of code?

like image 955
nadieh Avatar asked Jul 16 '13 08:07

nadieh


1 Answers

You want to split the problem up. First define a scale for your heatmap that maps 0-1 to your colours. Then define a second (dynamic) scale that maps your dataset to 0-1. You can then combine the scales to paint your shapes.

var colours = ["#6363FF", "#6373FF", "#63A3FF", "#63E3FF", "#63FFFB", "#63FFCB",                "#63FF9B", "#63FF6B", "#7BFF63", "#BBFF63", "#DBFF63", "#FBFF63",                 "#FFD363", "#FFB363", "#FF8363", "#FF7363", "#FF6364"];  var heatmapColour = d3.scale.linear()   .domain(d3.range(0, 1, 1.0 / (colours.length - 1)))   .range(colours);  // dynamic bit... var c = d3.scale.linear().domain(d3.extent(dataset)).range([0,1]);  // use the heatmap to fill in a canvas or whatever you want to do... canvas.append("svg:rect")   .data(dataset)   .enter()   // snip...   .style("fill", function(d) {      return heatmapColour(c(d)); 

Plus you can use the d3.extent function to get the min and max of the dataset in one go.

like image 70
dwxw Avatar answered Oct 04 '22 07:10

dwxw