d3 / d3-color Goto Github PK
View Code? Open in Web Editor NEWColor spaces! RGB, HSL, Cubehelix, CIELAB, and more.
Home Page: https://d3js.org/d3-color
License: ISC License
Color spaces! RGB, HSL, Cubehelix, CIELAB, and more.
Home Page: https://d3js.org/d3-color
License: ISC License
Coming in CSS Color Module Level 4:
It would be lovely to have documentation for the argument ranges of the hcl color space, as there is for the other color spaces.
Any possibility / support for adding a convenience method to return the colour in hex format?
I am working on a color library that aims to support all the CSS Color Level 4 formats, and would love to contribute to d3-color with some updates:
rgb(255 255 255 / 0.1)
, etc.)And could add HSV and HSI color spaces.
(+ more as I sort them out)
I was wondering which of these are in the scope of d3-color and whether I can submit PRs.
Thanks!
I propose we replace as follows:
And in the future, we’ll refer to CIEXYZ, CIELUV, and CIELCh_uv.
https://bottosson.github.io/posts/oklab/
Here's a list of the design choices behind oklab:
Seems like whenever I have a color where the saturation is 0% or the lightness is 0% or 100%, I get NaN
values in the returned color object.
Easiest to see the various examples here:
https://observablehq.com/d/f7636f7695376a03
But, for example:
d3.hsl('#ffffff')
returns {h: NaN, s: NaN, l: 1, opacity: 1}
IM trying to use this as the documentation suggests but when I create any color.hex() is throwing an error that it is not a function.
var white = d3.color("white"); console.log(white.hex());// Uncaught TypeError: white.hex is not a function
As defined here:
https://www.w3.org/TR/css-color-4/#color-conversion-code
https://observablehq.com/@mbostock/lab-and-rgb
function rgb_lrgb1(v) {
return v <= 0.04045 ? v / 12.92 : ((v + 0.055) / 1.055) ** 2.4;
}
function lrgb_rgb1(v) {
return v <= 0.0031308 ? 12.92 * v : 1.055 * (v ** (1 / 2.4)) - 0.055;
}
Related d3/d3-interpolate#66.
While investigating why d3's lab()
method gives subtly different results than, for example, Wolfram Alpha, I came to understand d3-color is missing a chromatic adaptation between the D65 (sRGB) and D50 (Lab) illuminants:
The process should be: Lab ↔ XYZ (D50) ↔ XYZ(D65) ↔ RGB
I'm not sure how important this adaptation is to the purpose of the library, but it boils down to using the matrices from this page:
const d50_to_d6 = ({ x, y, z }) => ({
x: x * 0.9555766 - y * 0.0230393 + z * 0.0631636,
y: x * -0.0282895 + y * 1.0099416 + z * 0.0210077,
z: x * 0.0122982 - y * 0.0204830 + z * 1.3299098
});
const d65_to_d50 = ({ x, y, z }) => ({
x: x * 1.0478112 + y * 0.0228866 - z * 0.0501270,
y: x * 0.0295424 + y * 0.9904844 - z * 0.0170491,
z: x * -0.0092345 + y * 0.0150436 + z * 0.7521316
});
Can you create a transpiled version of this project to your bower repo for browsers that arent es6 compliant?
Seems like we could make a cubehelix colorspace.
Most importantly: Thanks for your work on d3! 🎉 , ❤️ and 🥇!
I was trying to use d3-color
for sRGB to CIE-L*a*b* conversions today:
$ node
> const d3 = require("d3-color")
undefined
> d3.lab(0,100,100).rgb()
Rgb {
r: 109.26297015067321,
g: -126.7018621426472,
b: -236.7921286790844,
opacity: 1 }
> d3.lab(50,-50,-50).rgb()
Rgb {
r: -868.5123725460351,
g: 143.16534084117143,
b: 203.4499609542193,
opacity: 1 }
You expect L*a*b* values to be [[0-100], [-100,100], [-100,100]]
, correct? What colorspace are these RGB values in? I was expecting [0,255]
.
Am I using the API incorrectly?
(This is with node v8.9.0, fwiw)
This hack is a bit messy and error-prone when creating a custom build.
It would be nice to have a method to convert an hsl color into its css representation. A similar API is available in chroma.js
chroma.hsl(216, 1, 0.2).css('hsl')
"hsl(215.88,100%,20%)"
This link is not loading for me: https://www.mrao.cam.ac.uk/~dag/CUBEHELIX/
Firstly, thank you @mbostock for all of your incredible work, every time i have no clue how i am going to achieve something, it seems that d3 has already created a solution.
One small issue i have spotted is that when creating a d3.hcl object (example used is d3.hcl(15,100,65)) and converting to either rgb or hex (using both .rgb or d3.rgb()), it provides the wrong values. Output from this conversion is #FF0077 and it should be #F8766D.
Tested with d3 5.9.2 & 6.2.0
Edit: The conversion seems to be the same as Chroma.js so maybe this isn't a d3 issue? The output varies massively to this http://hclwizard.org/hclcolorpicker/ which i think is using R to generate the colors / graphics
var c = d3.hsl("#fafafa");
console.log(c) // {h: NaN,l: 0.9803921568627451,opacity: 1, s: 0}
h maybe 0
I'm not sure if it's an actual issue because I don't know the browser support for this but Map isn't supported in IE10- and in IE11, Map.prototype.set
does't return this
.
Have you considered parsing strings with alpha channels? I know they wouldn't map to hex values, but it would be pretty cool if the alpha channel was stripped out and it returned a valid color (and not null
).
Great work on these modules, really digging it.
Maybe this should be in d3-scale, but it would be nice to have some standard Cubehelix color scales:
var defaultCubehelix = color.interpolateCubehelix(
color.cubehelix(300, 0.5, 0.0),
color.cubehelix(-240, 0.5, 1.0)
);
var perceptualRainbow1 = color.interpolateCubehelix(
color.cubehelix(-100, 0.75, 0.35),
color.cubehelix(80, 1.50, 0.8)
);
var perceptualRainbow2 = color.interpolateCubehelix(
color.cubehelix(80, 1.50, 0.8),
color.cubehelix(260, 0.75, 0.35)
);
This is not an "issue" per se with d3-color, but just an idea / research problem that you may want to consider.
I always thought it would be great to have an algorithm that automagically picks N distinct colors that are as far apart perceptually as possible, for representing categorical values. Perhaps d3.scale.category20()
and friends fills this need currently in practice, but I feel like there should be an algorithm for this.
Here is a first attempt at such an algorithm that places points on a circle in LAB space (L is fixed, and the points vary only in (A, B), so they have equal luminance but different hue) http://bl.ocks.org/curran/dd73d3d8925cdf50df86.
Perhaps a better solution would be use Mitchell’s best-candidate algorithm for generating a Poisson-disc distribution in a limited region of (A, B) color space (perhaps a circle?), where the user could specify as input a fixed L value and the desired number of distinct colors. Also Lloyd relaxation might be another nice way to do this.
The API documentation might look something like this:
color.distinct(n, [L])
Returns an array of n
colors that are perceptually distinct. If L
is specified, it controls the fixed L value in LAB color space that the algorithm uses. If L is not specified, it defaults to 50.
Just an idea.
It's great to see all this activity on the new D3, excited to try it out!
README says:
Colors are now validated upon construction.
In fact they are clamped, not validated.
IMHO clamping isn't a good idea for RGB constructor, it hides "invalid" LAB/HCL colors instead of notifying about them.
Would you mind throwing exception or returning special value for invalid colors?
It is the only way to check whether LAB/HCL color is "valid" or not.
I'm using this kind of validation here:
https://github.com/devgru/postcss-color-hcl/blob/master/index.js#L22
Looking through the other pull requests on d3-color, I realized the approach for this repo is to keep a fairly minimal API and prefer creating separate plugins for the other color spaces. To that end, I'll close my vague issue #41 and propose and addition to the README that links to these other related repos, which I just realized exist:
(and any others I may be missing)
I'll gladly do the PR if that's okay!
Per #33 (comment), d3-color should support CIELUV in addition to CIELAB, and for compatibility with R, should redefine d3.hcl as polar CIELUV, but preserve d3.lch as polar CIELAB. We should also expose CIEXYZ for completeness.
When using an alpha value with d3.rgb
, via rgba
or hsla
colors strings, the color values return NaN
.
Is this expected behavior?
tested on
[email protected]
d3.rgb('hsla(240,100%,25%,0)');
// returns
{
r: NaN,
b: NaN,
g: NaN,
opacity: 0,
}
d3.rgb('rgba(0,0,0,0)');
// returns
{
r: NaN,
b: NaN,
g: NaN,
opacity: 0,
}
Also interesting to note that the behavior of non-zero, but close to zero, alpha values return the expected color.
d3.rgb('rgba(0,0,0,0.001)');
// returns
{
r: 0,
b: 0,
g: 0,
opacity: 0.001,
}
The Cubehelix color scheme allows a γ (gamma) parameter. I’m not sure how best to represent this concept if we define Cubehelix as a colorspace. Probably the colorspace assumes γ = 1, but then we allow interpolateCubehelixGamma(γ)? Ugh, with #4 we’ll also need interpolateCubehelixGammaLong.
Similar to color.brighter, but for succinctly modifying the opacity channel. It could return a new color whose opacity is max(0, min(1, this.opacity - delta)).
Possibly a better perceptual colorspace than Lab/Lch and Cubehelix?
This is just a naive question I wasn't able to get an answer from Google about, but wondering why HUSL space isn't included. It claims to offer a uniform lightness color space like HCL/LAB.
There's an interpolator for V3. Is there a reason not to use on one's own in colorizing maps?
http://www.hsluv.org/comparison/
https://npm.hotlibs.com/d3-interpolate-husl/package/0.1.0
@mbostock Note the updated repo is below.
The current definition obliterates the constructor
property.
when i use d3.color parse rgba(255,255,255,0)
, the result of r
,g
,b
is NaN.
why the a
is 0, the r
,g
,b
is NaN.
What is the desired behaviour of brightening black colour? Right now it will return black.
const brighter = d3.rgb("#000000").brighter(); // {b: 0, g: 0, opacity: 1, r: 0}
The following is a valid color (black with 50% opacity) but will not be recognized:
d3.color("rgba(0,0,0,.5)") === null // true
It seems that at least one digit is always required before the decimal point. I believe this can be fixed in the corresponding regex.
It’s useful to sometimes take the longer path when interpolating hue. For example, hue in the default cubehelix ramp goes through 540°. But this need extends beyond cubehelix—it seems reasonable to allow “long” hue interpolation in other cylindrical colorspaces, such as HCL and HSL, too.
This means: 1. Color instances in those spaces must be capable of representing hues outside of [0°,360°). Having hue default to that range when converting from another colorspace seems reasonable, though. 2. We need both “short” and “long” forms of interpolation for cylindrical colorspaces. It seems reasonable to default to short.
(I suppose it would also be possible to default to “long” if the change in hue is greater than or equal to 360°. But… that seems a little brittle, since you definitely might want to use “long” hue interpolation when the hue delta is in [180°,360°), too. So probably best to always make it explicit.)
CSS Color Module Level 4 adds these.
To reproduce:
console.log(d3.color("#fff1").formatRgb()); // rgba(255, 255, 255, 0.06666666666666667)
console.log(d3.color("#fff1").formatHex()); // #ffffff <-- shouldn't this be #ffffff11?
I'd expect that formatHex
would preserve opacity just as formatRgb
does; however, opacity is clearly ignored in the function definition
Line 266 in e87dc62
In the spirit of I couldn't help it I've ported all the color difference metrics to work with d3-color here 👉 https://github.com/danburzo/d3-color-difference
Out of them the euclidean distances are trivial to compute by end-users, and from the rest CIEDE2000 is supposedly the most accurate, and a hassle to implement. May be a good addition to d3-color itself, or is it preferable as a separate package?
(Oooh, I missed this notebook!)
In R, fixup defaults to TRUE. We need some equivalent to this (but faster, hopefully, at least using binary search):
function fixup(c) {
while (!c.displayable()) --c.c;
return c;
}
This makes a pretty big difference if you want to, say, emulate ggplot2’s hue color scale.
I may have missed it, but It seems there is no native way to convert from rgb or others to hexadecimal.
This can however be quite handy. See : https://jsfiddle.net/Mottie/xcqpF/1/light/
Hi Mike,
Application was working fine until the new release of d3 color version(1.4.0). As soon as this new version has come, kubernetes started failing with below mentioned error where as same code is working fine in local. After lot of research we could identify the issue and as an interim fix we are overriding with older version "1.3.0" and it is working fine now. Request you to extend your help on this.
They currently do, but I don’t think it makes sense. It only makes sense for RGB because of machine limitations. I suppose we could force the luminance to be non-negative, but I don’t think there’s any reason to limit the maximum value to 100.
Related d3/d3#517.
Some new color space: https://www.osapublishing.org/oe/fulltext.cfm?uri=oe-25-13-15131&id=368272
Here python implementation https://github.com/nschloe/colorio
Maybe d3 can support it?
Convertion to HSL gives unexpected results. Consider:
import { hcl } from "d3-color";
const c = hcl(200, 100, 150);
console.log(c.formatHex());
console.log(c.formatRgb());
console.log(c.formatHsl());
Actual output in Chrome 86 on Mac:
#00ffff
rgb(0, 255, 255)
hsl(180.380573958081, -163.7644455443205%, -293.13231330226415%)
The hex and rgb notations are the same color: bright cyan. The HSL notation is different. The documentation also says the saturation and lightness values are clamped to the interval of 0-100, but they are not. Do I misunderstand how non-displayable colors are converted or is there a bug in the hsl converstion here?
Here’s another way to look at this:
const a = rgb(0, 255, 255);
const b = rgb(hcl(200, 100, 150));
a.formatRgb(); // rgb(0, 255, 255)
b.formatRgb(); // rgb(0, 255, 255)
a.formatHsl(); // hsl(180, 100%, 50%)
b.formatHsl(); // hsl(180.380573958081, -163.7644455443205%, -293.13231330226415%)
in the color picker s has range [0,2]
but after i Played with it looks like values more then 2 are allowed
d3Color.cubehelix(370,3.4,0.15).toString() // "rgb(200, 0, 0)"
d3Color.cubehelix(370,3,0.15).toString() // "rgb(181, 0, 0)"
d3Color.cubehelix(370,2,0.15).toString() // "rgb(133, 5, 0)"
d3Color.cubehelix(370,1,0.15).toString() // "rgb(86, 22, 0)"
So I do not quite understand how is that working, can you add some comments or link to some resources (I'm familiar with original page and paper, but I have not seen implementation of it as a color space), (I'm thinking on implementing it as part of purescript-contrib/purescript-colors#31)
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.