Last active
August 29, 2015 14:01
-
-
Save nitaku/3f02ab54b366477d8f30 to your computer and use it in GitHub Desktop.
HCL decomposition: cubehelix
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
### Cubehelix plugin, from http://bl.ocks.org/mbostock/11413789 ### | |
` | |
(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(gamma) { | |
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, gamma), | |
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; | |
} | |
})(); | |
` | |
colorify = d3.scale.cubehelix() | |
.domain([0, 255]) | |
palette = d3.range(256).map (i) -> colorify(i) | |
svg = d3.select('svg') | |
svg.selectAll('.colored_band') | |
.data(palette) | |
.enter().append('rect') | |
.attr('class', 'colored_band') | |
.attr('x', (d,i)->32+3.5*i) | |
.attr('y', 21) | |
.attr('width', 3.5) | |
.attr('height', 120) | |
.attr('fill', (d)->d ) | |
svg.selectAll('.hue_band') | |
.data(palette) | |
.enter().append('rect') | |
.attr('class', 'hue_band') | |
.attr('x', (d,i)->32+3.5*i) | |
.attr('y', 166) | |
.attr('width', 3.5) | |
.attr('height', 60) | |
.attr('fill', (d) -> | |
hcl = d3.hcl(d) | |
hcl.c = 60 | |
hcl.l = 60 | |
return hcl | |
) | |
svg.selectAll('.chroma_band') | |
.data(palette) | |
.enter().append('rect') | |
.attr('class', 'chroma_band') | |
.attr('x', (d,i)->32+3.5*i) | |
.attr('y', 237) | |
.attr('width', 3.5) | |
.attr('height', 116) | |
.attr('fill', (d) -> | |
hcl = d3.hcl(d) | |
hcl.l = hcl.c/1.4 | |
hcl.h = 80 | |
hcl.c = 25 | |
return hcl | |
) | |
svg.selectAll('.luminance_band') | |
.data(palette) | |
.enter().append('rect') | |
.attr('class', 'luminance_band') | |
.attr('x', (d,i)->32+3.5*i) | |
.attr('y', 364) | |
.attr('width', 3.5) | |
.attr('height', 116) | |
.attr('fill', (d) -> | |
hcl = d3.hcl(d) | |
hcl.c = 0 | |
return hcl | |
) | |
x = d3.scale.linear() | |
.domain([0,255]) | |
.range([32, 928]) | |
h_y = d3.scale.linear() | |
.domain([0,360]) | |
.range([166+60, 166]) | |
c_y = d3.scale.linear() | |
.domain([0,150]) | |
.range([237+116, 237]) | |
l_y = d3.scale.linear() | |
.domain([0,100]) | |
.range([364+116, 364]) | |
h_line = d3.svg.line() | |
.x((_, i) -> x(i)) | |
.y((d, i) -> | |
# work around NaN error | |
if i is 0 | |
return h_y(0) | |
h = d3.hcl(d).h | |
return h_y( if h > 0 then h else h+360 ) | |
) | |
c_line = d3.svg.line() | |
.x((_, i) -> x(i)) | |
.y((d, i) -> | |
# work around NaN error | |
if i is 0 | |
return c_y(0) | |
c_y( d3.hcl(d).c ) | |
) | |
l_line = d3.svg.line() | |
.x((_, i) -> x(i)) | |
.y((d, i) -> l_y( d3.hcl(d).l ) ) | |
svg.append('path') | |
.datum(palette) | |
.attr('class', 'hue') | |
.attr('d', h_line) | |
svg.append('path') | |
.datum(palette) | |
.attr('class', 'chroma') | |
.attr('d', c_line) | |
svg.append('path') | |
.datum(palette) | |
.attr('class', 'luminance') | |
.attr('d', l_line) | |
h_axis = d3.svg.axis() | |
.scale(h_y) | |
.tickValues([0,360]) | |
.orient('right') | |
.tickSize(3,5) | |
c_axis = d3.svg.axis() | |
.scale(c_y) | |
.ticks(4) | |
.orient('right') | |
.tickSize(3,5) | |
l_axis = d3.svg.axis() | |
.scale(l_y) | |
.ticks(2) | |
.orient('right') | |
.tickSize(3,5) | |
svg.append('g') | |
.attr('class', 'axis') | |
.attr('transform', 'translate(932,0)') | |
.call(h_axis) | |
svg.append('g') | |
.attr('class', 'axis') | |
.attr('transform', 'translate(932,0)') | |
.call(c_axis) | |
svg.append('g') | |
.attr('class', 'axis') | |
.attr('transform', 'translate(932,0)') | |
.call(l_axis) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
body { | |
background: #272822; | |
margin: 0; | |
padding: 0; | |
} | |
svg { | |
background: white; | |
} | |
.label { | |
text-anchor: middle; | |
font-size: 24px; | |
} | |
rect { | |
shape-rendering: crispEdges; | |
} | |
path { | |
fill: none; | |
} | |
path.hue { | |
stroke: white; | |
stroke-width: 1; | |
} | |
path.chroma { | |
stroke: #FF3D00; | |
stroke-width: 1; | |
} | |
path.luminance { | |
stroke: black; | |
stroke-width: 0.6; | |
} | |
.axis .domain, .axis .tick line { | |
stroke: black; | |
shape-rendering: crispEdges; | |
} | |
.axis { | |
font-size: 8px; | |
font-family: sans-serif; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8"> | |
<meta name="description" content="HCL decomposition: cubehelix" /> | |
<title>HCL decomposition: cubehelix</title> | |
<link rel="stylesheet" href="index.css"> | |
<script src="http://d3js.org/d3.v3.min.js"></script> | |
</head> | |
<body> | |
<svg height="500" width="960"> | |
<text class="label" x="16" y="198" dy="0.35em">H</text> | |
<text class="label" x="16" y="295" dy="0.35em">C</text> | |
<text class="label" x="16" y="420" dy="0.35em">L</text> | |
</svg> | |
<script src="index.js"></script> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* Cubehelix plugin, from http://bl.ocks.org/mbostock/11413789 | |
*/ | |
(function() { | |
(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(gamma) { | |
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, gamma), | |
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; | |
} | |
})(); | |
; | |
var c_axis, c_line, c_y, colorify, h_axis, h_line, h_y, l_axis, l_line, l_y, palette, svg, x; | |
colorify = d3.scale.cubehelix().domain([0, 255]); | |
palette = d3.range(256).map(function(i) { | |
return colorify(i); | |
}); | |
svg = d3.select('svg'); | |
svg.selectAll('.colored_band').data(palette).enter().append('rect').attr('class', 'colored_band').attr('x', function(d, i) { | |
return 32 + 3.5 * i; | |
}).attr('y', 21).attr('width', 3.5).attr('height', 120).attr('fill', function(d) { | |
return d; | |
}); | |
svg.selectAll('.hue_band').data(palette).enter().append('rect').attr('class', 'hue_band').attr('x', function(d, i) { | |
return 32 + 3.5 * i; | |
}).attr('y', 166).attr('width', 3.5).attr('height', 60).attr('fill', function(d) { | |
var hcl; | |
hcl = d3.hcl(d); | |
hcl.c = 60; | |
hcl.l = 60; | |
return hcl; | |
}); | |
svg.selectAll('.chroma_band').data(palette).enter().append('rect').attr('class', 'chroma_band').attr('x', function(d, i) { | |
return 32 + 3.5 * i; | |
}).attr('y', 237).attr('width', 3.5).attr('height', 116).attr('fill', function(d) { | |
var hcl; | |
hcl = d3.hcl(d); | |
hcl.l = hcl.c / 1.4; | |
hcl.h = 80; | |
hcl.c = 25; | |
return hcl; | |
}); | |
svg.selectAll('.luminance_band').data(palette).enter().append('rect').attr('class', 'luminance_band').attr('x', function(d, i) { | |
return 32 + 3.5 * i; | |
}).attr('y', 364).attr('width', 3.5).attr('height', 116).attr('fill', function(d) { | |
var hcl; | |
hcl = d3.hcl(d); | |
hcl.c = 0; | |
return hcl; | |
}); | |
x = d3.scale.linear().domain([0, 255]).range([32, 928]); | |
h_y = d3.scale.linear().domain([0, 360]).range([166 + 60, 166]); | |
c_y = d3.scale.linear().domain([0, 150]).range([237 + 116, 237]); | |
l_y = d3.scale.linear().domain([0, 100]).range([364 + 116, 364]); | |
h_line = d3.svg.line().x(function(_, i) { | |
return x(i); | |
}).y(function(d, i) { | |
var h; | |
if (i === 0) { | |
return h_y(0); | |
} | |
h = d3.hcl(d).h; | |
return h_y(h > 0 ? h : h + 360); | |
}); | |
c_line = d3.svg.line().x(function(_, i) { | |
return x(i); | |
}).y(function(d, i) { | |
if (i === 0) { | |
return c_y(0); | |
} | |
return c_y(d3.hcl(d).c); | |
}); | |
l_line = d3.svg.line().x(function(_, i) { | |
return x(i); | |
}).y(function(d, i) { | |
return l_y(d3.hcl(d).l); | |
}); | |
svg.append('path').datum(palette).attr('class', 'hue').attr('d', h_line); | |
svg.append('path').datum(palette).attr('class', 'chroma').attr('d', c_line); | |
svg.append('path').datum(palette).attr('class', 'luminance').attr('d', l_line); | |
h_axis = d3.svg.axis().scale(h_y).tickValues([0, 360]).orient('right').tickSize(3, 5); | |
c_axis = d3.svg.axis().scale(c_y).ticks(4).orient('right').tickSize(3, 5); | |
l_axis = d3.svg.axis().scale(l_y).ticks(2).orient('right').tickSize(3, 5); | |
svg.append('g').attr('class', 'axis').attr('transform', 'translate(932,0)').call(h_axis); | |
svg.append('g').attr('class', 'axis').attr('transform', 'translate(932,0)').call(c_axis); | |
svg.append('g').attr('class', 'axis').attr('transform', 'translate(932,0)').call(l_axis); | |
}).call(this); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment