dc.js making a color range between two colours

1k Views Asked by At

I'm letting users select one of four numerical series from a dropdown to drive the colouring of circles in a bubble chart. (There are similar dropdowns for radius, x and y.)

d3.select("select#colour").on('change',function(d) {
  var tempIndex = this.selectedIndex;
  yearlyBubbleChart.colorAccessor(function (p) {
    return p.value[optionArray[0][tempIndex]];
  });
  yearlyBubbleChart.colors(colorbrewer[optionArray[7][tempIndex]][optionArray[8][tempIndex]]);
  yearlyBubbleChart.colorDomain([optionArray[5][tempIndex][0], optionArray[5][tempIndex][1]]);
});

To do this, I'm using colorAccessor, colors and colorDomain, in that order. (I've noticed in some cases that the order of these three matters.) I'd like users to be able to select min and max colours, and drive the colouring from that. For this I need to colour the bubbles from just two colours, e.g. ['white','blue']. Higher numeric values would be proportionately more blue.

It seems a really easy thing to do but I can't work it out. Supplying an array of two colours is generally used to alternate, and in a bubble chart the minimum bubble is white and the rest are blue. How do I get a continuous colour range by inputting just two colours?

Thanks

1

There are 1 best solutions below

1
On BEST ANSWER

d3 knows how to interpolate between colors. You can create a linear scale where the range (output values) are colors.

var colorScale = d3.scale.linear()
  .domain([0, 1])
  .range(['white', 'blue'])

Below is an example which shows various colors generated by the scale at set percentages (where 0% is all white and 100% is all blue).

var ele = d3.select('#holder');

var width = 500;
var height = 25;
var margin = 30;

// these are the values in the domain 0 to 1 for which
// we will draw bands (whose color is somewhere between
// white and blue).
var percents = [0, 0.1, 0.25, 0.5, 0.75, 0.9, 1];

// a continuous scale from 'white' to 'blue'
var colorScale = d3.scale.linear()
  .domain([0, 1])
  .range(['white', 'blue'])

var x = d3.scale.ordinal()
  .domain(percents)
  .rangeBands([0, width]);

var g = ele.append('svg')
  .attr('width', width + 2*margin)
  .attr('height', height + 2*margin)
  .append('g')
  .attr('transform', 'translate(' + margin + ',' + margin + ')');

// axis
var axis = d3.svg.axis()
  .orient('bottom')
  .scale(x)
  .tickFormat(d3.format('.2f'))

g.append('g')
  .classed('x axis', true)
  .call(axis);

var values = g.append('g')
  .classed('percents', true)
  .selectAll('g.percent')
  .data(percents)
  .enter().append('g')
  .classed('percent', true)
  .attr('transform', function(d){
    return 'translate(' + x(d) + ',-10)';
  });

var bandwidth = x.rangeBand();
values.append('rect')
  .attr('x', 0)
  .attr('width', bandwidth)
  .attr('y', -25)
  .attr('height', 25)
  // use the colorScale to determine the color of each band
  .style('fill', colorScale);
.domain, .tick line {
  fill: none;
  stroke: black;
  stroke-width: 1px;
  shape-rendering: crispEdges;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<div id='holder'></div>