Starting with xy coordinates I would like to plot a chromaticity diagram displaying just the sRGB gamut portion of the CIE xy chromaticity diagram.

For each xy coordinate of my diagram I need to determine the corresponding Y value to obtain the complete xyY representation, from which XYZ tristimulus values can be calculated and finally sRGB values derived.

By starting with the known sRGB Red, Green, Blue and white values: #FF0000, #00FF00, #0000FF, #FFFFFF respectively I can use the Bradford matrix to deduce their XYZ tristimulus values and thus their xyY representations.

But starting with xy coordinates is there a method for determining the Y component?

ps. If you are able to add new tags, could you possibly add some tags like 'colorimetry', 'chromaticity-diagram' and 'color-models'?


The Y component is for you to choose, because for a given x,y pair, depending on Y, the colour may or may not lie within the sRGB volume.

It is possible to know whether there is at least one sRGB colour that will map to a given x,y pair, though. Note that if linear RGB values (R,G,B) are transformed to (x,y,Y), then (a*R,a*G,a*B) are transformed to (x,y,a*Y). Multiplying each of the RGB triplets with a constant doest not affect x or y.

So one way to take an (x,y) pair and find out whether it can be obtained from an sRGB value is:

  • set Y = 100
  • convert (x,y,Y) back to (X,Y,Z)
  • convert (X,Y,Z) to linear RGB (R,G,B)
  • if one of R, G or B is negative, we are out of the sRGB space
  • otherwise, divide each of R, G and B by the largest of the three
  • optionally, convert linear (R,G,B) to gamma-corrected sRGB values

Here is some GLSL code that does the job:

vec4 color = vec4(0.0, 0.0, 0.0, 1.0);

vec3 xyY = vec3(pass_Position.xy, 100.0);
vec3 XYZ = xyY.z * vec3(xyY.x / xyY.y, 1.0, (1.0 - xyY.x - xyY.y) / xyY.y);

mat3 XYZtoRGB = mat3(vec3( 0.032406f, -0.009689f,  0.000557f),
                     vec3(-0.015372f,  0.018758f, -0.002040f),
                     vec3(-0.004986f,  0.000415f,  0.010570f));

vec3 RGB = XYZtoRGB * XYZ;

if (RGB.x >= 0.0 && RGB.y >= 0.0 && RGB.z >= 0.0)
    RGB /= max(RGB.x, max(RGB.y, RGB.z));
    vec3 sRGB = pow(RGB, vec3(1.0 / 2.4));
    color.xyz = sRGB;

And this is the result:

sRGB gamut

  • $\begingroup$ Hi Sam! thank you very much for your answer. Sorry for the slow reply I'm still new to working with colour models and wasn't sure if I had more questions but I think I'm ok for now. Thanks again! $\endgroup$ – Duncan Gravill Feb 26 '13 at 13:34
  • $\begingroup$ Thanks, this was incredibly helpful. I'd been trying to render something similar for quite a while and kept getting stuck on "I know what x and y are, but what should Y be?". I made a codepen that renders this using an HTML canvas: codepen.io/bantic/pen/oyRXOX?editors=1010 $\endgroup$ – bantic Jul 4 '18 at 17:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.