More examples of the d3.interpolateCubehelix plugin, replicating four Python cubehelix examples. In the last two examples, a polylinear scale creates a diverging cubehelix color ramp, and an approximate recreation of Matteo Niccoli’s perceptual rainbow.
| (function() { | |
| var radians = Math.PI / 180; | |
| d3.scale.cubehelix = function() { | |
| return d3.scale.linear() | |
| .range([d3.hsl(300, .5, 0), d3.hsl(-240, .5, 1)]) | |
| .interpolate(d3.interpolateCubehelix); | |
| }; | |
| d3.interpolateCubehelix = d3_interpolateCubehelix(1); | |
| d3.interpolateCubehelix.gamma = d3_interpolateCubehelix; | |
| function d3_interpolateCubehelix(γ) { | |
| return function(a, b) { | |
| a = d3.hsl(a); | |
| b = d3.hsl(b); | |
| var ah = (a.h + 120) * radians, | |
| bh = (b.h + 120) * radians - ah, | |
| as = a.s, | |
| bs = b.s - as, | |
| al = a.l, | |
| bl = b.l - al; | |
| if (isNaN(bs)) bs = 0, as = isNaN(as) ? b.s : as; | |
| if (isNaN(bh)) bh = 0, ah = isNaN(ah) ? b.h : ah; | |
| return function(t) { | |
| var h = ah + bh * t, | |
| l = Math.pow(al + bl * t, γ), | |
| a = (as + bs * t) * l * (1 - l); | |
| return "#" | |
| + hex(l + a * (-0.14861 * Math.cos(h) + 1.78277 * Math.sin(h))) | |
| + hex(l + a * (-0.29227 * Math.cos(h) - 0.90649 * Math.sin(h))) | |
| + hex(l + a * (+1.97294 * Math.cos(h))); | |
| }; | |
| }; | |
| } | |
| function hex(v) { | |
| var s = (v = v <= 0 ? 0 : v >= 1 ? 255 : v * 255 | 0).toString(16); | |
| return v < 0x10 ? "0" + s : s; | |
| } | |
| })(); |
| <!DOCTYPE html> | |
| <meta charset="utf-8"> | |
| <style> | |
| body { | |
| font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; | |
| } | |
| .ramp { | |
| position: absolute; | |
| } | |
| .ramp div { | |
| position: absolute; | |
| top: 0; | |
| right: 20px; | |
| } | |
| .ramp[name='Reversed'] div { | |
| color: #fff; | |
| } | |
| </style> | |
| <body> | |
| <script src="//d3js.org/d3.v3.min.js"></script> | |
| <script src="cubehelix.js"></script> | |
| <script> | |
| var ramps = [ | |
| { | |
| name: "Default", | |
| color: d3.scale.cubehelix() | |
| }, | |
| { | |
| name: "Reversed", | |
| color: d3.scale.cubehelix() | |
| .domain([1, 0]) | |
| }, | |
| { | |
| name: "Hue [276°, 96°]", | |
| color: d3.scale.cubehelix() | |
| .range([d3.hsl(276, .6, 0), d3.hsl(96, .6, 1)]) | |
| }, | |
| { | |
| name: "Hue [-120°, 60°]", | |
| color: d3.scale.cubehelix() | |
| .range([d3.hsl(-120, .6, 0), d3.hsl(60, .6, 1)]) | |
| }, | |
| { | |
| name: "Hue [-40°, 60°, 160]", | |
| color: d3.scale.cubehelix() | |
| .domain([0, .5, 1]) | |
| .range([d3.hsl(-40, .6, .3), d3.hsl(60, .6, 1), d3.hsl(160, .6, .3)]) | |
| }, | |
| { | |
| name: "Rainbow", | |
| color: d3.scale.cubehelix() | |
| .range([d3.hsl(270, .75, .35), d3.hsl(70, 1.5, .8)]) | |
| } | |
| ]; | |
| var y = d3.scale.ordinal() | |
| .domain(ramps.map(function(d) { return d.name; })) | |
| .rangeRoundBands([0, 500], .1); | |
| var margin = y.range()[0], | |
| width = 960 - margin - margin, | |
| height = y.rangeBand(); | |
| var ramp = d3.select("body").selectAll(".ramp") | |
| .data(ramps) | |
| .enter().append("div") | |
| .attr("class", "ramp") | |
| .attr("name", function(d) { return d.name; }) | |
| .style("width", width + "px") | |
| .style("height", height + "px") | |
| .style("left", margin + "px") | |
| .style("top", function(d) { return y(d.name) + "px"; }); | |
| var canvas = ramp.append("canvas") | |
| .attr("width", width) | |
| .attr("height", 1) | |
| .style("width", width + "px") | |
| .style("height", height + "px") | |
| .each(function(d) { | |
| var context = this.getContext("2d"), | |
| image = context.createImageData(width, 1); | |
| for (var i = 0, j = -1, c; i < width; ++i) { | |
| c = d3.rgb(d.color(i / (width - 1))); | |
| image.data[++j] = c.r; | |
| image.data[++j] = c.g; | |
| image.data[++j] = c.b; | |
| image.data[++j] = 255; | |
| } | |
| context.putImageData(image, 0, 0); | |
| }); | |
| ramp.append("div") | |
| .style("line-height", height + "px") | |
| .text(function(d) { return d.name; }); | |
| </script> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment