block by cpbotha 6831663

ColorBrewer sequential single hue scales vs. d3 interpolators.

Full Screen

index.html

<!DOCTYPE html>
<html>

<head>
    <meta http-equiv="Content-Type" content="text/html;charset=utf-8">
    <title>Comparison of d3 colour interpolators with colorbrewer sequential single hue scales</title>
</head>

<style>
body {
  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
  width: 960px;
  height: 500px;
  position: relative;
}
</style>

<body>
    <h3>Comparison of d3 colour interpolators with colorbrewer sequential single hue scales</h3>
    
    <p><a href="//colorbrewer2.org/">ColorBrewer</a> is a fantastic
    resource for great colour schemes. However, its schemes contain up to a
    maximum of 9 colours. Sometimes, one would like to have a similar looking
    scheme available for continuous data.</p>

    <p>I wanted to see which of d3's interpolators yielded linear scales that
    were visually closest to the ColorBrewer ones. For all of the single hue
    sequential scales, the HSL interpolator <i>seems</i> to be visually
    closest. The perceptually more responsible interpolators, namely HCL and
    L*a*b*, yield results that are visually less similar.</p>

    <p>(Yes, of course you could just use d3.scale.quantize if you wanted your
    linear domain to map to the colorbrewer colours, but I wanted to see a
    linear range as well.)</p>

    <p>Comment on the <a
    href="//vxlabs.com/2013/10/04/d3-interpolators-vs-colorbrewer-single-hue-sequential-scales/">blog
    post</a>, see <a href="//bl.ocks.org/cpbotha">my other bl.ocks</a> or link up with <a
    href="//twitter.com/cpbotha">@cpbotha</a> on twitter.</p>


<div id="chart">
</div>

<script src="//d3js.org/d3.v3.min.js"></script>
<script src="//d3js.org/colorbrewer.v1.min.js"></script>
<script type="text/javascript" src="colorbrewer_interpolate.js"></script>

</body>
</html>

colorbrewer_interpolate.js

// comparison of different d3 colour interpolators with
// colorbrewer sequential single-hue scales
//
// -- http://twitter.com/cpbotha

var numC = 9;
var data = d3.range(numC);

var showColourInterpolations = function(name, cbMap) {
    var rectHeight = 50,
        w = 960;
    
    var chart = d3.select("#chart");
    chart.append('h4').text(name);

    var svg=chart.append("svg");

    var x = d3.scale.ordinal()
        .domain(data)
        .rangeRoundBands([0, w], 0.1);

    var colour = d3.scale.linear()
        .domain(d3.extent(data))
        .range([cbMap[numC][0], cbMap[numC][numC - 1]]);



    var addScale = function (y, colourFunc, name) {
        svg.append('text').attr("x", x(0)).attr("y", y-15).text(name);

        var textrectg = svg.append('g').selectAll("g")
            .data(data)
        .enter().append("g")
            .attr("transform", function(d) { return "translate(" + x(d) + "," + y + ")"; });
            
        textrectg.append("rect")
                //.attr("x", function(d) {return x(d); })
                //.attr("y", y)
                .attr("width", x.rangeBand())
                .attr("height", rectHeight)
                .attr("fill", colourFunc );

        textrectg.append("text")
                .text(colourFunc);
    }

    var colourBrewer = function (d) {
        return cbMap[numC][d];
    }
    // https://github.com/mbostock/d3/wiki/Transitions#wiki-d3_interpolateLab
    var colourLab = colour.copy().interpolate(d3.interpolateLab);
    // https://github.com/mbostock/d3/wiki/Transitions#wiki-d3_interpolateHcl
    var colourHcl = colour.copy().interpolate(d3.interpolateHcl);
    // https://github.com/mbostock/d3/wiki/Transitions#wiki-d3_interpolateRgb
    var colourRgb = colour.copy().interpolate(d3.interpolateRgb);
    // https://github.com/mbostock/d3/wiki/Transitions#wiki-d3_interpolateHsl
    var colourHsl = colour.copy().interpolate(d3.interpolateHsl);

    var cfuncs = [['brewer', colourBrewer], 
              ['L*a*b*', colourLab], 
              ['HCL', colourHcl],
              ['RGB', colourRgb], 
              ['HSL', colourHsl]];

    for (var i = 0; i < cfuncs.length; i++) {
        addScale(30 + i * (rectHeight + 30), cfuncs[i][1], cfuncs[i][0]);
    }
}

mapNames = ['Blues', 'Greens', 'Oranges', 'Purples', 'Reds'];
mapNames.forEach(function (mapName) {showColourInterpolations(mapName, colorbrewer[mapName]); });