Skip to content

Instantly share code, notes, and snippets.

@amergin
Last active Aug 29, 2015
Embed
What would you like to do?
Stretch available color range to be used based on the values
// Specs:
// - As a default, the colour range should be scaled so, that at least 70% (..ish) of the colour range is available for the data shown.
// Example: we have a map with lowest positive correlation at r=0.85 and highest at r=0.99 while the negative correlations span from r=-0.2 to r=-0.35. The desired colour range would then be as follows:
// 100% red at r=0.99,
// 30% red at r=0.85,
// white at r=0,
// 30% blue at r=-0.2 and
// 100% blue at r=-0.35.
function CustomScale() {
var obj = {},
priv = {
coordinates: [],
interpolated: {},
lower: {
min: null,
max: null
},
upper: {
min: null,
max: null
},
constant: {
lower: null,
middle: null,
upper: null,
threshold: 0.3
}
};
function getName(coord, reverse) {
if(reverse) {
return [coord.y, coord.x].join("|");
} else {
return [coord.x, coord.y].join("|");
}
}
function computeInterpolated() {
var thre = priv.constant.threshold,
correlation;
_.each(priv.coordinates, function(coord) {
correlation = coord.corr;
if(correlation > 0) {
priv.interpolated[getName(coord)] = (thre) + (1-thre) * ( correlation - priv.upper.min ) / (priv.upper.max - priv.upper.min);
}
else if(correlation < 0) {
priv.interpolated[getName(coord)] = -(thre) - (1-thre) * ( correlation - priv.lower.min ) / (priv.lower.max - priv.lower.min);
}
});
}
function computeMaxMin() {
var lowerExtent = d3.extent(priv.coordinates, function(d) {
if(d.corr > 0) { return undefined; }
return d.corr;
});
var upperExtent = d3.extent(priv.coordinates, function(d) {
if(d.corr < 0) { return undefined; }
return d.corr;
});
priv.lower.min = _.isUndefined(lowerExtent[0]) ? priv.constant.lower : lowerExtent[0];
priv.lower.max = _.isUndefined(lowerExtent[1]) ? priv.constant.upper : lowerExtent[1];
priv.upper.min = upperExtent[0];
priv.upper.max = upperExtent[1];
}
obj.lower = function(x) {
if(!arguments.length) { return priv.constant.lower; }
priv.constant.lower = x;
return obj;
};
obj.middle = function(x) {
if(!arguments.length) { return priv.constant.middle; }
priv.constant.middle = x;
return obj;
};
obj.upper = function(x) {
if(!arguments.length) { return priv.constant.upper; }
priv.constant.upper = x;
return obj;
};
obj.threshold = function(x) {
if(!arguments.length) { return priv.constant.threshold; }
priv.constant.threshold = x;
return obj;
};
// get color value
obj.color = function(obj) {
var red, green, blue,
interp = priv.interpolated[getName(obj)];
interp = _.isUndefined(interp) ? priv.interpolated[getName(obj, true)] : interp;
if(interp > 0) {
// upper, red
red = 255;
green = 255 * (1 - interp);
blue = 255 * (1 - interp);
} else {
// lower, blue
red = 255 * (1 + interp);
green = 255 * (1 + interp);
blue = 255;
}
return d3.rgb(red, green, blue).toString();
};
obj.coordinates = function(x) {
if(!arguments.length) { return priv.coordinates; }
priv.coordinates = x;
computeMaxMin();
computeInterpolated();
return obj;
};
return obj;
}
var scale = new CustomScale()
.lower(-1)
.middle(0)
.upper(1)
.threshold(0.25);
// call to get value
var color = scale.color();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment