1

So I am trying to create a color scale with d3, but I'm just confused on what scale to use exactly. I'm coloring things based off pearson correlation and would like the following bins:

[-1,-0.5,-0.3,0,0.3,0.5,1]

Pearson correlation is continuous from -1 to 1, but the different values can mean higher correlations. For example:

high correlation: [-1,-.5] & [.5,1]

moderate correlation: [-.5,-.3] & [.3,.5]

low correlation: [-.3,0] & [0,.3]

I'm trying to make a diverging color scale with the following colors:

colors = ["#a6611a", "#dfc27d", "#f5f5f5", "#80cdc1", "#018571"]

Basically, for each level of correlation, I want it to be mapped to one of those exact colors. So, high correlations would be mapped to #a6611a and #018571, moderate ones would get mapped to #dfc27d and #80cdc1, and so on. I pretty much want:

continuous input => discrete output 

But I'm confused on how to do this with d3 color scales.... I know there are the quantize and quantile scales as described here but I dont know if that's what I'm looking fo.

My understanding of those is that they take in a continuous input and split the domain into either uniform segments (quantize) or by domain quantiles... however thats not what I want. I want to put in a range from [-1,1] and always get #a6611a and #018571 for input in [-1,-.5] & [.5,1] and so on. Is this possible to do with either of those scales?

I tried:

var colorScale = d3.scale.quantile()
                      .domain([-1,-0.5,-0.3,0,0.3,0.5,1])
                      .range(colors);

But if I do that, I end up with colorScale(.29) = #80cdc1 when I want colorScale(.29) = "#f5f5f5".

I also tried a linear scale:

var colorScaleLinear = d3.scale.linear()
                      .domain([-1,-0.5,-0.3,0,0.3,0.5,1])
                      .range(colors);

But in that case, I will get my data mapped to colors that don't necessarily have to be one of my 5 colors. Example: colorScaleLinear(.29) = #058774

I'm just confused if there is a way to do this in d3, and I'm new to color scales so after spending hours on this I'm just not sure what to try... what color scale should I be using? Is there a way to set the output to be a discrete set of colors?

Any help would be greatly appreciated, thanks!!

EDIT Would threshold scales be the way to go?

Community
  • 1
  • 1
ocean800
  • 3,489
  • 13
  • 41
  • 73
  • 1
    Yes, you have to use a threshold scale, but the domain should have less elements than the range. – Gerardo Furtado Apr 05 '17 at 14:58
  • @GerardoFurtado Is there any reason why the domain needs to have less values? – ocean800 Apr 05 '17 at 15:00
  • 1
    That's pure math: If the number of values in the scale’s range is N+1, the number of values in the scale’s domain must be N. You have 5 colors, right? So, you should have 4 values in the domain, let's say A, B, C and D. Less than A, first color, Between A and B, second color, between B and C, third color, between C and D, forth color, more than D, fifth color. Did you get it? – Gerardo Furtado Apr 05 '17 at 15:03
  • @GerardoFurtado Yes, makes sense thanks :) – ocean800 Apr 05 '17 at 15:05

1 Answers1

1

You want to use d3.scale.threshold().

var q=d3.scale.threshold()
 .domain([-1,-0.499999,-0.2999999,0.3,0.5,1])
 .range( ["#a6611a","#a6611a", "#dfc27d", "#f5f5f5", "#80cdc1", "#018571","#018571"]);


a=[-0.5,-0.50001,-0.4999,-0.3,-0.2999,0,0.299,0.3001,0.5001,1];
a.forEach(function(i){
  console.log(i, q(i));
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
var q=d3.scale.threshold()
.domain([-1,-0.499999,-0.2999999,0.3,0.5,1])
.range( ["#a6611a","#a6611a", "#dfc27d", "#f5f5f5", "#80cdc1", "#018571","#018571"]);
ocean800
  • 3,489
  • 13
  • 41
  • 73
Ken
  • 4,367
  • 4
  • 28
  • 41
  • Thanks for the answer! However, I dont think this is what I'm looking for. For example, I want `q(.29) = #f5f5f5`, but in this case it would map to `#80cdc1` ? I don't want equally sized bins, I want to be able to decide what my bins are if that makes sense. – ocean800 Apr 05 '17 at 14:52
  • Sorry, I glossed over the bit about pearson correlation. I understand. – Ken Apr 05 '17 at 14:57
  • @ocean800 I've changed the answer to use threshold. On testing It seems to do what you need – Ken Apr 05 '17 at 15:12
  • I didn't think of just setting the first and last colors to just the same colors and was having issues on q(1)... cleared it up, thanks! :) – ocean800 Apr 05 '17 at 15:17