Skip to content

Commit 582d2d8

Browse files
authored
Merge pull request #1090 from plotly/contour-rgba-colorscale
Centralise color scale function creation
2 parents e01cb00 + cb86fac commit 582d2d8

File tree

18 files changed

+755
-129
lines changed

18 files changed

+755
-129
lines changed
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/**
2+
* Copyright 2012-2016, Plotly, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the MIT license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
9+
10+
'use strict';
11+
12+
/**
13+
* Extract colorscale into numeric domain and color range.
14+
*
15+
* @param {array} scl colorscale array of arrays
16+
* @param {number} cmin minimum color value (used to clamp scale)
17+
* @param {number} cmax maximum color value (used to clamp scale)
18+
*/
19+
module.exports = function extractScale(scl, cmin, cmax) {
20+
var N = scl.length,
21+
domain = new Array(N),
22+
range = new Array(N);
23+
24+
for(var i = 0; i < N; i++) {
25+
var si = scl[i];
26+
27+
domain[i] = cmin + si[0] * (cmax - cmin);
28+
range[i] = si[1];
29+
}
30+
31+
return {
32+
domain: domain,
33+
range: range
34+
};
35+
};

src/components/colorscale/index.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,6 @@ exports.getScale = require('./get_scale');
2727

2828
exports.flipScale = require('./flip_scale');
2929

30-
exports.makeScaleFunction = require('./make_scale_function');
30+
exports.extractScale = require('./extract_scale');
31+
32+
exports.makeColorScaleFunc = require('./make_color_scale_func');
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
/**
2+
* Copyright 2012-2016, Plotly, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the MIT license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
9+
10+
'use strict';
11+
12+
var d3 = require('d3');
13+
var tinycolor = require('tinycolor2');
14+
var isNumeric = require('fast-isnumeric');
15+
16+
var Color = require('../color');
17+
18+
/**
19+
* General colorscale function generator.
20+
*
21+
* @param {object} specs output of Colorscale.extractScale or precomputed domain, range.
22+
* - domain {array}
23+
* - range {array}
24+
*
25+
* @param {object} opts
26+
* - noNumericCheck {boolean} if true, scale func bypasses numeric checks
27+
* - returnArray {boolean} if true, scale func return 4-item array instead of color strings
28+
*
29+
* @return {function}
30+
*/
31+
module.exports = function makeColorScaleFunc(specs, opts) {
32+
opts = opts || {};
33+
34+
var domain = specs.domain,
35+
range = specs.range,
36+
N = range.length,
37+
_range = new Array(N);
38+
39+
for(var i = 0; i < N; i++) {
40+
var rgba = tinycolor(range[i]).toRgb();
41+
_range[i] = [rgba.r, rgba.g, rgba.b, rgba.a];
42+
}
43+
44+
var _sclFunc = d3.scale.linear()
45+
.domain(domain)
46+
.range(_range)
47+
.clamp(true);
48+
49+
var noNumericCheck = opts.noNumericCheck,
50+
returnArray = opts.returnArray,
51+
sclFunc;
52+
53+
if(noNumericCheck && returnArray) {
54+
sclFunc = _sclFunc;
55+
}
56+
else if(noNumericCheck) {
57+
sclFunc = function(v) {
58+
return colorArray2rbga(_sclFunc(v));
59+
};
60+
}
61+
else if(returnArray) {
62+
sclFunc = function(v) {
63+
if(isNumeric(v)) return _sclFunc(v);
64+
else if(tinycolor(v).isValid()) return v;
65+
else return Color.defaultLine;
66+
};
67+
}
68+
else {
69+
sclFunc = function(v) {
70+
if(isNumeric(v)) return colorArray2rbga(_sclFunc(v));
71+
else if(tinycolor(v).isValid()) return v;
72+
else return Color.defaultLine;
73+
};
74+
}
75+
76+
// colorbar draw looks into the d3 scale closure for domain and range
77+
78+
sclFunc.domain = _sclFunc.domain;
79+
80+
sclFunc.range = function() { return range; };
81+
82+
return sclFunc;
83+
};
84+
85+
function colorArray2rbga(colorArray) {
86+
var colorObj = {
87+
r: colorArray[0],
88+
g: colorArray[1],
89+
b: colorArray[2],
90+
a: colorArray[3]
91+
};
92+
93+
return tinycolor(colorObj).toRgbString();
94+
}

src/components/colorscale/make_scale_function.js

Lines changed: 0 additions & 47 deletions
This file was deleted.

src/components/drawing/index.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -331,7 +331,10 @@ drawing.tryColorscale = function(cont, contIn, prefix) {
331331
Lib.nestedProperty(contIn, prefix + 'cmin').set(min);
332332
Lib.nestedProperty(contIn, prefix + 'cmax').set(max);
333333
}
334-
return Colorscale.makeScaleFunction(scl, min, max);
334+
335+
return Colorscale.makeColorScaleFunc(
336+
Colorscale.extractScale(scl, min, max)
337+
);
335338
}
336339
else return Lib.identity;
337340
};

src/lib/gl_format_color.js

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
var tinycolor = require('tinycolor2');
1313
var isNumeric = require('fast-isnumeric');
1414

15-
var makeScaleFunction = require('../components/colorscale/make_scale_function');
15+
var Colorscale = require('../components/colorscale');
1616
var colorDflt = require('../components/color/attributes').defaultLine;
1717

1818
var str2RgbaArray = require('./str2rgbarray');
@@ -42,8 +42,12 @@ function formatColor(containerIn, opacityIn, len) {
4242
var sclFunc, getColor, getOpacity, colori, opacityi;
4343

4444
if(containerIn.colorscale !== undefined) {
45-
sclFunc = makeScaleFunction(
46-
containerIn.colorscale, containerIn.cmin, containerIn.cmax
45+
sclFunc = Colorscale.makeColorScaleFunc(
46+
Colorscale.extractScale(
47+
containerIn.colorscale,
48+
containerIn.cmin,
49+
containerIn.cmax
50+
)
4751
);
4852
}
4953
else sclFunc = validateColor;

src/traces/choropleth/plot.js

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,8 @@ var Axes = require('../../plots/cartesian/axes');
1515
var Fx = require('../../plots/cartesian/graph_interact');
1616
var Color = require('../../components/color');
1717
var Drawing = require('../../components/drawing');
18+
var Colorscale = require('../../components/colorscale');
1819

19-
var getColorscale = require('../../components/colorscale/get_scale');
20-
var makeScaleFunction = require('../../components/colorscale/make_scale_function');
2120
var getTopojsonFeatures = require('../../lib/topojson_utils').getTopojsonFeatures;
2221
var locationToFeature = require('../../lib/geo_location_utils').locationToFeature;
2322
var arrayToCalcItem = require('../../lib/array_to_calc_item');
@@ -151,11 +150,15 @@ plotChoropleth.style = function(geo) {
151150
var trace = calcTrace[0].trace,
152151
s = d3.select(this),
153152
marker = trace.marker || {},
154-
markerLine = marker.line || {},
155-
zmin = trace.zmin,
156-
zmax = trace.zmax,
157-
scl = getColorscale(trace.colorscale),
158-
sclFunc = makeScaleFunction(scl, zmin, zmax);
153+
markerLine = marker.line || {};
154+
155+
var sclFunc = Colorscale.makeColorScaleFunc(
156+
Colorscale.extractScale(
157+
trace.colorscale,
158+
trace.zmin,
159+
trace.zmax
160+
)
161+
);
159162

160163
s.selectAll('path.choroplethlocation')
161164
.each(function(pt) {

src/traces/contour/make_color_map.js

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,7 @@
1010
'use strict';
1111

1212
var d3 = require('d3');
13-
14-
var getColorscale = require('../../components/colorscale/get_scale');
15-
13+
var Colorscale = require('../../components/colorscale');
1614

1715
module.exports = function makeColorMap(trace) {
1816
var contours = trace.contours,
@@ -22,7 +20,7 @@ module.exports = function makeColorMap(trace) {
2220
nc = Math.floor((end + cs / 10 - start) / cs) + 1,
2321
extra = contours.coloring === 'lines' ? 0 : 1;
2422

25-
var scl = getColorscale(trace.colorscale),
23+
var scl = trace.colorscale,
2624
len = scl.length;
2725

2826
var domain = new Array(len),
@@ -69,10 +67,10 @@ module.exports = function makeColorMap(trace) {
6967
}
7068
}
7169

72-
var colorMap = d3.scale.linear()
73-
.interpolate(d3.interpolateRgb)
74-
.domain(domain)
75-
.range(range);
76-
77-
return colorMap;
70+
return Colorscale.makeColorScaleFunc({
71+
domain: domain,
72+
range: range,
73+
}, {
74+
noNumericCheck: true
75+
});
7876
};

src/traces/heatmap/colorbar.js

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,17 @@
99

1010
'use strict';
1111

12-
var d3 = require('d3');
1312
var isNumeric = require('fast-isnumeric');
1413

1514
var Lib = require('../../lib');
1615
var Plots = require('../../plots/plots');
17-
var getColorscale = require('../../components/colorscale/get_scale');
16+
var Colorscale = require('../../components/colorscale');
1817
var drawColorbar = require('../../components/colorbar/draw');
1918

2019

2120
module.exports = function colorbar(gd, cd) {
2221
var trace = cd[0].trace,
2322
cbId = 'cb' + trace.uid,
24-
scl = getColorscale(trace.colorscale),
2523
zmin = trace.zmin,
2624
zmax = trace.zmax;
2725

@@ -36,9 +34,16 @@ module.exports = function colorbar(gd, cd) {
3634
}
3735

3836
var cb = cd[0].t.cb = drawColorbar(gd, cbId);
39-
cb.fillcolor(d3.scale.linear()
40-
.domain(scl.map(function(v) { return zmin + v[0] * (zmax - zmin); }))
41-
.range(scl.map(function(v) { return v[1]; })))
37+
var sclFunc = Colorscale.makeColorScaleFunc(
38+
Colorscale.extractScale(
39+
trace.colorscale,
40+
zmin,
41+
zmax
42+
),
43+
{ noNumericCheck: true }
44+
);
45+
46+
cb.fillcolor(sclFunc)
4247
.filllevels({start: zmin, end: zmax, size: (zmax - zmin) / 254})
4348
.options(trace.colorbar)();
4449
};

src/traces/heatmap/plot.js

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,11 @@
99

1010
'use strict';
1111

12-
var d3 = require('d3');
1312
var tinycolor = require('tinycolor2');
1413

1514
var Registry = require('../../registry');
1615
var Lib = require('../../lib');
17-
var getColorscale = require('../../components/colorscale/get_scale');
16+
var Colorscale = require('../../components/colorscale');
1817
var xmlnsNamespaces = require('../../constants/xmlns_namespaces');
1918

2019
var maxRowLength = require('./max_row_length');
@@ -45,9 +44,6 @@ function plotOne(gd, plotinfo, cd) {
4544
}
4645

4746
var z = cd[0].z,
48-
min = trace.zmin,
49-
max = trace.zmax,
50-
scl = getColorscale(trace.colorscale),
5147
x = cd[0].x,
5248
y = cd[0].y,
5349
isContour = Registry.traceIs(trace, 'contour'),
@@ -170,15 +166,14 @@ function plotOne(gd, plotinfo, cd) {
170166
canvas.height = canvasH;
171167
var context = canvas.getContext('2d');
172168

173-
// interpolate for color scale
174-
// use an array instead of color strings, so we preserve alpha
175-
var s = d3.scale.linear()
176-
.domain(scl.map(function(si) { return si[0]; }))
177-
.range(scl.map(function(si) {
178-
var c = tinycolor(si[1]).toRgb();
179-
return [c.r, c.g, c.b, c.a];
180-
}))
181-
.clamp(true);
169+
var sclFunc = Colorscale.makeColorScaleFunc(
170+
Colorscale.extractScale(
171+
trace.colorscale,
172+
trace.zmin,
173+
trace.zmax
174+
),
175+
{ noNumericCheck: true, returnArray: true }
176+
);
182177

183178
// map brick boundaries to image pixels
184179
var xpx,
@@ -289,7 +284,7 @@ function plotOne(gd, plotinfo, cd) {
289284

290285
function setColor(v, pixsize) {
291286
if(v !== undefined) {
292-
var c = s((v - min) / (max - min));
287+
var c = sclFunc(v);
293288
c[0] = Math.round(c[0]);
294289
c[1] = Math.round(c[1]);
295290
c[2] = Math.round(c[2]);

0 commit comments

Comments
 (0)