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

additional colour space for d3 #579

Closed
wants to merge 30 commits into from
Closed

Conversation

justincormack
Copy link

Here is a patch for adding CIE Lab colourspace to d3.

There is a gist up http://bl.ocks.org/1958838 showing the improved perceptual colours for brighter and darker, will add some more for the hues.

@justincormack
Copy link
Author

Ah I just saw that there is a pull request for HSV too... will add interpolators as per the comment there.

@mbostock
Copy link
Member

mbostock commented Mar 3, 2012

Nice work, and thank for you the contribution!

Related #183 - d3.lab
Related #517 - d3.hsv
Related https://github.com/jrus/chromatist

Do you have any recommendation as to how to choose between XYZ, CIE Lab or CIE LCh? Is there a pressing need for all three, or did you include them for completeness' sake? My main reservation here is feature creep. Still, given the interest I could be convinced of the usefulness of including at least one perceptually-based colorspace in core. (Probably CIE Lab?) The other colorspaces are useful, but I wonder if it might be better to have a d3-chromatist plugin that adds additional colorspaces on demand?

Implementation comment: if we have more than two color spaces, then having methods on every color space to convert to every other color space probably won't scale. Fortunately, it's also unnecessary because all of them must support a toString() method that returns the "#rrggbb" format (for browser compatibility); as long as all the constructors support parsing the same format and converting to the respective colorspace, then we only have to deal with conversion to and from RGB.

So, we shouldn't remove the existing methods for backwards-compatibility, but you should only have to implement an rgb() and a toString() method on the new colorspaces, and leave the conversion to the constructors. For example, to go from xyz to lab, you might say myLab = d3.lab(myXyz) rather than myLab = myXyz.lab().

/cc @jrus @jheer @alex

@justincormack
Copy link
Author

XYZ was only really there as CIELab is defined as a transform from it. I don't think there is much of a use case for it directly, so will remove it.

The other two are just the linear and cylindrical versions of the same space. Some operations only really make sense in the linear CIELab, like interpolation, but other things like changing hue make more sense in cylindrical coordinates. One option would be to have one type but expose the cylindrical operations on it too. I think this is probably the nicest to work with, so will give it a try.

@justincormack
Copy link
Author

Ok so now XYZ is gone. CIELab now has hue() and chroma() methods that can return or set the hue and chroma, which is the only reason I had CIELch, so that is gone too. Added Lab interpolator. It is pretty small, so doesn't look too much like bloat in the core.

@justincormack
Copy link
Author

Some thoughts at this point:

  1. For compatibility with existing hsl, I should probably switch the chroma() function to scale as 0..1 not 0..100, and accept percentages. But then the lightness probably ought to be changed, or add a lightness() function. Will think about this a bit more.
  2. If you take the view that HSL and HSV are not colour spaces, just representations of RGB, then adding hue(), saturation(), lightness() and value() functions to d3.rgb would be an option, and then d3.hsl could just be a constructor for rgb objects and not an object of its own. This would simplify the situation to just two spaces, one device space and one perceptual, with a small amount of backwards compatibility breakage.
  3. Chromatist seems a bit complex for most use cases in d3.

@jrus
Copy link

jrus commented Mar 8, 2012

It’s quite helpful to be able to interpolate in terms of both LCh and Lab*. The former is useful when it’s a desirable feature to keep chroma high (for instance, when interpolating from red to blue, it might be nice to go through a colorful purple instead of a dull purplish-gray). As a precedent, ArcGIS allows the use of either in its “color ramp” pickers.

Regardless of which are supported, CIELAB → RGB transformations have to have some knowledge of gamut and some gamut mapping algorithm for out-of-gamut colors. The most obvious choices are (a) the nearest in-gamut point between a color and the grey of the same lightness, and (b) the nearest in-gamut point between a color and middle gray (L* = 50).

HSL/HSV/RGB are quite perniciously bad tools for visualizations (and anything with human input involved, really), and the documentation should clearly recommend against them.

Chroma (C) should scale the same as a/b*, or else it’s entirely confusing what it means. CIELAB has no “maximum” chroma, and 100 is not in any way special. It should not accept percentages.

You might be right that CIECAM02 is more complex than necessary for many D3 applications.

@jrus
Copy link

jrus commented Mar 8, 2012

One more thing that should really be clarified: I assume the CIELAB here is relative to a reference D65 white point? This is fine, but it should be pointed out in the docs that this makes for different output than Photoshop, which uses a chromatic adaptation transform (the Bradford CAT) to adapt XYZ colors from a source color space’s white point (e.g. sRGB’s D65) to D50, and then computes CIELAB coordinates based on that D50-adapted XYZ.

@justincormack
Copy link
Author

Thanks for those comments they are very helpful. Will work on the issues raised, should be able to add both interpolators for example.

@justincormack
Copy link
Author

Having used this as is for a bit, it is annoying not to have a way to do LCh initialization. Not sure whether to do an "lch(...)" style one like rgb has or go back to having an LCh colourspace. Doing interpolation across LCh will be a little slower without a colourspace for it too.

@mbostock
Copy link
Member

mbostock commented Apr 2, 2012

Would you be interested in exposing this as a D3 plugin? I've created a repository at d3/d3-plugins, and I could give you push access to submit your code there. To help you get started, I made some scaffolding of a d3.cie plugin to show you what I was imagining; you're of course welcome to propose an alternative structure, but I think it could fit in nicely.

@justincormack
Copy link
Author

Yeah sure that looks good, will see how it works out but certainly makes sense.

@mbostock
Copy link
Member

mbostock commented Apr 5, 2012

Great! I just gave you push privileges. Let me know if you want a hand.

@mbostock
Copy link
Member

I combined your code with @jheer's earlier implementation of Lab color and it is now available as the d3.cie plugin. Here's an example demonstrating Lab and LCH interpolation.

If you want to make any edits, go ahead, you have the powah!

@mbostock mbostock closed this Jun 28, 2012
@justincormack
Copy link
Author

Will find some time to look at this soon! Been tied up in other projects but its not forgotten!

@jrus
Copy link

jrus commented Jun 29, 2012

Main thing that would be very helpful if people plan to start using this is some kind of gamut mapping algorithm. Otherwise, they’re going to do LCh interpolation from one bright color to another, and end up with all kinds of weird artifacts along the way. Otherwise, it’s nice that D3 is trying to put some better color spaces in. :-)

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

Successfully merging this pull request may close these issues.

None yet

3 participants