Is your feature request related to a problem? Please describe.
While @encodable/color exposes all D3 color maps, the main library is not using the interpolator with scaleSequential
. Instead scaleLinear
is used with a range of the scheme colors. However, this effectively results in a linear scale between the first two colors of the scheme only. Sequential multi-hue color scales are thus not supported.
Describe the solution you'd like
My understanding is that we'd have to extend encodable's createScale()
:
function createScale<Output extends DefaultOutput>(config: ScaleConfig<Output>) {
const { range } = config;
// Handle categorical color scales
// An ordinal scale without specified range
// is assumed to be a color scale.
if (config.type === ScaleType.ORDINAL && typeof range === 'undefined') {
const scheme = 'scheme' in config ? config.scheme : undefined;
const resolve = Encodable.getCategoricalColorScaleResolver();
let colorScale: ScaleOrdinal<StringLike, string>;
if (typeof scheme === 'undefined') {
colorScale = resolve({});
} else if (isSchemeParams(scheme)) {
colorScale = resolve(scheme);
} else {
colorScale = resolve({ name: scheme });
}
const castedColorScale = (colorScale as unknown) as ScaleOrdinal<StringLike, Output>;
applyDomain(config, castedColorScale);
return castedColorScale;
}
// Handle sequential color scales
if (config.type === ScaleType.SEQUENTIAL && config?.scheme && isSchemeParams(config?.scheme)) {
const scheme = config.scheme;
let count = isContinuousScaleConfig(config) && domain
? domain.length
: scheme.count || 2;
let extent = scheme.extent
? scheme.extent
: [0, 1];
const schemeObject = Encodable.resolveColorScheme({
name: scheme.name,
type: ScaleType.SEQUENTIAL
});
if (typeof schemeObject !== 'undefined' && schemeObject.type === ScaleType.SEQUENTIAL) {
const wrappedScheme = wrapColorScheme(schemeObject);
const colors = wrappedScheme.getColors(count, extent) as Output[];
const interpolator = piecewise(interpolateRgb, colors);
const colorScale = (scaleSequential(interpolator) as unknown) as ScaleLinear<string, string>;
applyDomain(config, colorScale);
return colorScale;
}
}
const scale = createScaleFromScaleType<Output>(config.type);
return updateScale(scale, config);
}
I probably missed a few aspects here but I am happy to give this a shot if you accept PRs.
Describe alternatives you've considered
Alternatively, we could probably extend createScaleFromScaleType()
to support scaleSequential
via ScaleType
like VegaLite. However, I don't think encodable supports applying interpolators anywhere so it might be easier to do the above route.