Skip to content
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

Support for multi-hue color maps #189

Open
flekschas-ozette opened this issue Jan 12, 2022 · 0 comments
Open

Support for multi-hue color maps #189

flekschas-ozette opened this issue Jan 12, 2022 · 0 comments

Comments

@flekschas-ozette
Copy link

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant