Skip to content

Centralise color scale function creation #1090

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Oct 27, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions src/components/colorscale/extract_scale.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/**
* Copyright 2012-2016, Plotly, Inc.
* All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/


'use strict';

/**
* Extract colorscale into numeric domain and color range.
*
* @param {array} scl colorscale array of arrays
* @param {number} cmin minimum color value (used to clamp scale)
* @param {number} cmax maximum color value (used to clamp scale)
*/
module.exports = function extractScale(scl, cmin, cmax) {
var N = scl.length,
domain = new Array(N),
range = new Array(N);

for(var i = 0; i < N; i++) {
var si = scl[i];

domain[i] = cmin + si[0] * (cmax - cmin);
range[i] = si[1];
}

return {
domain: domain,
range: range
};
};
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK sure - we could imagine having this one also include opts and call the other one, since I can't see us ever using this without wrapping it in makeColorScaleFunc... but then naming gets confusing. meh, lets leave it as you have it here.

4 changes: 3 additions & 1 deletion src/components/colorscale/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,6 @@ exports.getScale = require('./get_scale');

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

exports.makeScaleFunction = require('./make_scale_function');
exports.extractScale = require('./extract_scale');

exports.makeColorScaleFunc = require('./make_color_scale_func');
94 changes: 94 additions & 0 deletions src/components/colorscale/make_color_scale_func.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/**
* Copyright 2012-2016, Plotly, Inc.
* All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/


'use strict';

var d3 = require('d3');
var tinycolor = require('tinycolor2');
var isNumeric = require('fast-isnumeric');

var Color = require('../color');

/**
* General colorscale function generator.
*
* @param {object} specs output of Colorscale.extractScale or precomputed domain, range.
* - domain {array}
* - range {array}
*
* @param {object} opts
* - noNumericCheck {boolean} if true, scale func bypasses numeric checks
* - returnArray {boolean} if true, scale func return 4-item array instead of color strings
*
* @return {function}
*/
module.exports = function makeColorScaleFunc(specs, opts) {
opts = opts || {};

var domain = specs.domain,
range = specs.range,
N = range.length,
_range = new Array(N);

for(var i = 0; i < N; i++) {
var rgba = tinycolor(range[i]).toRgb();
_range[i] = [rgba.r, rgba.g, rgba.b, rgba.a];
}

var _sclFunc = d3.scale.linear()
.domain(domain)
.range(_range)
.clamp(true);

var noNumericCheck = opts.noNumericCheck,
returnArray = opts.returnArray,
sclFunc;

if(noNumericCheck && returnArray) {
sclFunc = _sclFunc;
}
else if(noNumericCheck) {
sclFunc = function(v) {
return colorArray2rbga(_sclFunc(v));
};
}
else if(returnArray) {
sclFunc = function(v) {
if(isNumeric(v)) return _sclFunc(v);
else if(tinycolor(v).isValid()) return v;
else return Color.defaultLine;
};
}
else {
sclFunc = function(v) {
if(isNumeric(v)) return colorArray2rbga(_sclFunc(v));
else if(tinycolor(v).isValid()) return v;
else return Color.defaultLine;
};
}

// colorbar draw looks into the d3 scale closure for domain and range

sclFunc.domain = _sclFunc.domain;

sclFunc.range = function() { return range; };

return sclFunc;
};

function colorArray2rbga(colorArray) {
var colorObj = {
r: colorArray[0],
g: colorArray[1],
b: colorArray[2],
a: colorArray[3]
};

return tinycolor(colorObj).toRgbString();
}
47 changes: 0 additions & 47 deletions src/components/colorscale/make_scale_function.js

This file was deleted.

5 changes: 4 additions & 1 deletion src/components/drawing/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,10 @@ drawing.tryColorscale = function(cont, contIn, prefix) {
Lib.nestedProperty(contIn, prefix + 'cmin').set(min);
Lib.nestedProperty(contIn, prefix + 'cmax').set(max);
}
return Colorscale.makeScaleFunction(scl, min, max);

return Colorscale.makeColorScaleFunc(
Colorscale.extractScale(scl, min, max)
);
}
else return Lib.identity;
};
Expand Down
10 changes: 7 additions & 3 deletions src/lib/gl_format_color.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
var tinycolor = require('tinycolor2');
var isNumeric = require('fast-isnumeric');

var makeScaleFunction = require('../components/colorscale/make_scale_function');
var Colorscale = require('../components/colorscale');
var colorDflt = require('../components/color/attributes').defaultLine;

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

if(containerIn.colorscale !== undefined) {
sclFunc = makeScaleFunction(
containerIn.colorscale, containerIn.cmin, containerIn.cmax
sclFunc = Colorscale.makeColorScaleFunc(
Colorscale.extractScale(
containerIn.colorscale,
containerIn.cmin,
containerIn.cmax
)
);
}
else sclFunc = validateColor;
Expand Down
17 changes: 10 additions & 7 deletions src/traces/choropleth/plot.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,8 @@ var Axes = require('../../plots/cartesian/axes');
var Fx = require('../../plots/cartesian/graph_interact');
var Color = require('../../components/color');
var Drawing = require('../../components/drawing');
var Colorscale = require('../../components/colorscale');

var getColorscale = require('../../components/colorscale/get_scale');
var makeScaleFunction = require('../../components/colorscale/make_scale_function');
var getTopojsonFeatures = require('../../lib/topojson_utils').getTopojsonFeatures;
var locationToFeature = require('../../lib/geo_location_utils').locationToFeature;
var arrayToCalcItem = require('../../lib/array_to_calc_item');
Expand Down Expand Up @@ -151,11 +150,15 @@ plotChoropleth.style = function(geo) {
var trace = calcTrace[0].trace,
s = d3.select(this),
marker = trace.marker || {},
markerLine = marker.line || {},
zmin = trace.zmin,
zmax = trace.zmax,
scl = getColorscale(trace.colorscale),
sclFunc = makeScaleFunction(scl, zmin, zmax);
markerLine = marker.line || {};

var sclFunc = Colorscale.makeColorScaleFunc(
Colorscale.extractScale(
trace.colorscale,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah good catch, we've already done this at the supplyDefaults step so no need to repeat it anywhere else.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep, so many getColorscale were 🔪 in this PR.

trace.zmin,
trace.zmax
)
);

s.selectAll('path.choroplethlocation')
.each(function(pt) {
Expand Down
18 changes: 8 additions & 10 deletions src/traces/contour/make_color_map.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,7 @@
'use strict';

var d3 = require('d3');

var getColorscale = require('../../components/colorscale/get_scale');

var Colorscale = require('../../components/colorscale');

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

var scl = getColorscale(trace.colorscale),
var scl = trace.colorscale,
len = scl.length;

var domain = new Array(len),
Expand Down Expand Up @@ -69,10 +67,10 @@ module.exports = function makeColorMap(trace) {
}
}

var colorMap = d3.scale.linear()
.interpolate(d3.interpolateRgb)
.domain(domain)
.range(range);

return colorMap;
return Colorscale.makeColorScaleFunc({
domain: domain,
range: range,
}, {
noNumericCheck: true
});
};
17 changes: 11 additions & 6 deletions src/traces/heatmap/colorbar.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,17 @@

'use strict';

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

var Lib = require('../../lib');
var Plots = require('../../plots/plots');
var getColorscale = require('../../components/colorscale/get_scale');
var Colorscale = require('../../components/colorscale');
var drawColorbar = require('../../components/colorbar/draw');


module.exports = function colorbar(gd, cd) {
var trace = cd[0].trace,
cbId = 'cb' + trace.uid,
scl = getColorscale(trace.colorscale),
zmin = trace.zmin,
zmax = trace.zmax;

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

var cb = cd[0].t.cb = drawColorbar(gd, cbId);
cb.fillcolor(d3.scale.linear()
.domain(scl.map(function(v) { return zmin + v[0] * (zmax - zmin); }))
.range(scl.map(function(v) { return v[1]; })))
var sclFunc = Colorscale.makeColorScaleFunc(
Colorscale.extractScale(
trace.colorscale,
zmin,
zmax
),
{ noNumericCheck: true }
);

cb.fillcolor(sclFunc)
.filllevels({start: zmin, end: zmax, size: (zmax - zmin) / 254})
.options(trace.colorbar)();
};
25 changes: 10 additions & 15 deletions src/traces/heatmap/plot.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,11 @@

'use strict';

var d3 = require('d3');
var tinycolor = require('tinycolor2');

var Registry = require('../../registry');
var Lib = require('../../lib');
var getColorscale = require('../../components/colorscale/get_scale');
var Colorscale = require('../../components/colorscale');
var xmlnsNamespaces = require('../../constants/xmlns_namespaces');

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

var z = cd[0].z,
min = trace.zmin,
max = trace.zmax,
scl = getColorscale(trace.colorscale),
x = cd[0].x,
y = cd[0].y,
isContour = Registry.traceIs(trace, 'contour'),
Expand Down Expand Up @@ -170,15 +166,14 @@ function plotOne(gd, plotinfo, cd) {
canvas.height = canvasH;
var context = canvas.getContext('2d');

// interpolate for color scale
// use an array instead of color strings, so we preserve alpha
var s = d3.scale.linear()
.domain(scl.map(function(si) { return si[0]; }))
.range(scl.map(function(si) {
var c = tinycolor(si[1]).toRgb();
return [c.r, c.g, c.b, c.a];
}))
.clamp(true);
var sclFunc = Colorscale.makeColorScaleFunc(
Colorscale.extractScale(
trace.colorscale,
trace.zmin,
trace.zmax
),
{ noNumericCheck: true, returnArray: true }
);

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

function setColor(v, pixsize) {
if(v !== undefined) {
var c = s((v - min) / (max - min));
var c = sclFunc(v);
c[0] = Math.round(c[0]);
c[1] = Math.round(c[1]);
c[2] = Math.round(c[2]);
Expand Down
Loading