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

Multivariate Color Scheme #236

Open
curran opened this issue Jan 29, 2021 · 4 comments
Open

Multivariate Color Scheme #236

curran opened this issue Jan 29, 2021 · 4 comments

Comments

@curran
Copy link
Contributor

curran commented Jan 29, 2021

As a follow-up to discussion in d3/d3-scale-chromatic#32 , I'd like to pose the question of how to best calculate a multivariate color scheme. The use case is for building multivariate choropleth maps.

I'm investigating how one might approximate the colors of a dot density map, like this one.

image

The most sensible approach to me at the moment seems to be:

  • Define multiple single-hue color ramps that vary in opacity from 0 to 1, for each variable.
  • Blend those RGBA colors together.

Related:

@curran
Copy link
Contributor Author

curran commented Jan 29, 2021

Perhaps this implementation of a bivariate color scheme could be generalized to handle an arbitrary number of variables.

colors = blendMode => {
  const scale1 = chroma.scale([color1, lightest]).mode(colorMode).correctLightness().colors(rows)
  const scale2 = chroma.scale([color2, lightest]).mode(colorMode).correctLightness().colors(rows)
  
  const data = []
  
  for(let i = 0; i < rows; i++) {
    for(let j = 0; j < rows; j++) {
      data[i * rows + j] =  {
        color: chroma.blend(scale1[i], scale2[j], blendMode),
        x: i * size / rows,
        y: j * size / rows
      }
    }
  }
  
  return data
}

From https://observablehq.com/@benjaminadk/bivariate-choropleth-color-generator

This blends the colors using https://vis4.net/chromajs/#chroma-blend

@mbostock mbostock transferred this issue from d3/d3-scale-chromatic Jan 29, 2021
@mbostock
Copy link
Member

d3-scale-chromatic is for concrete color schemes; what you’re describing is not a specific color scheme but a strategy for encoding multivariate data as a color, so I’ve transferred this issue to d3-scale. However, I don’t have any plans to implement this feature in d3-scale either, since d3-scale is currently exclusively for one-dimensional encodings.

@curran
Copy link
Contributor Author

curran commented Jan 29, 2021

Got it. Thanks!

To clarify scope: the premise of this issue is to propose that d3-scale include some functionality for multivariate color scales/schemes.

I'll be investigating this design space in external work, and will post updates here if any concrete ideas come to mind for additions to d3-scale.

@curran
Copy link
Contributor Author

curran commented Feb 4, 2021

Here's a first stab at an idea for how to do this.

image

The approach here is to blend the colors together, using colorBlend.js.

const multivariateScale = (d) => {
  const colors = [
    whiteScale(whiteValue(d)),
    blackScale(blackValue(d)),
    asianScale(asianValue(d)),
  ];
  const blended = colors.map(rgba).reduce(colorBlend.multiply);
  const { r, g, b, a } = blended;
  return `rgba(${r},${g},${b},${a}`;
};

The color ramps are square root scales that go from transparent to opaque.

const whiteScale = scaleSqrt()
  .domain([0, maxValue])
  .range([transparent(whiteColor), opaque(whiteColor)]);

I started with a linear scale and randomly tried square root, and it looked better. Not grounded at all in best practices.

I'm interested in the larger conversation around best practices for this sort of thing. I have a hunch that this technique can be very powerful for certain datasets.

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

No branches or pull requests

2 participants