Tell me more ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

I am trying to visualize the visible spectrum using the built-in ColorData["VisibleSpectrum"] function which "colors based on light wavelength in nanometers". But I get wrong results for well-known pure colors. For example the yellow color has wavelength of 570–590 nm but ColorData["VisibleSpectrum"][580] returns green:

screenshot

Is it a bug? How to visualize the visible spectrum in Mathematica correctly?

share|improve this question
1  
The myriad of color spaces, conversions between them, monitor calibrations, our color perception... there are entire books on this. – VLC Oct 3 '12 at 14:52
1  
@VLC I understand but should not we expect to get the Yellow color when using such a function with its argument set to yellow wavelength? There already is the built-in color mapping and it works pretty well. – Alexey Popkov Oct 3 '12 at 14:58
1  
Related: CIE Chromaticity Diagram – Vitaliy Kaurov Oct 4 '12 at 10:05
The Java source code for generating the diagram in your edit seems to be using a linear interpolation... – 0x4A4D Oct 7 '12 at 13:51
@J.M. I just found it myself. I'll roll back the edit. – Alexey Popkov Oct 8 '12 at 7:27
show 1 more comment

6 Answers

up vote 10 down vote accepted

(too long for a comment)

Plot[{ColorData["VisibleSpectrum"][x][[1]],
      ColorData["VisibleSpectrum"][x][[2]],
      ColorData["VisibleSpectrum"][x][[3]]}, {x, 380, 750}, PlotStyle -> {Red, Green, Blue}]

RGB components of visible spectrum

It doesn't seem that you'll be able to obtain Yellow (RGBColor[1, 1, 0]) from ColorData["VisibleSpectrum"]; unfortunately, the docs say nothing about how they're blending the colors to produce "VisibleSpectrum".


Addendum:

Just to make this post less useless, here's a Mathematica implementation of Bruton's conversion algorithm:

brutonIntensity = Interpolation[{{380, 3/10}, {420, 1}, {700, 1}, {780, 3/10}},
                                InterpolationOrder -> 1];

brutonLambda[x_, γ_: 4/5] := Map[N[brutonIntensity[x] #]^γ &, 
    Blend[{{0, Magenta}, {3/20, Blue}, {11/40, Cyan}, {13/40, Green}, {1/2, Yellow},
           {53/80, Red}, {1, Red}}, Rescale[x, {380, 780}]]] /;
    380 <= x <= 780 && 0 < γ <= 1

Here's a gradient plot:

gradient plot for Bruton's scheme

and an RGB component plot:

RGB components for Bruton's scheme

I haven't fully investigated the method for converting wavelengths to CIE xyz coordinates; maybe one of these days...

share|improve this answer
3  
What others think that should look like: Approximate RGB values for Visible Wavelengths. Their code allows for RGBColor[1, 1, 0]. – sebhofer Oct 3 '12 at 16:16
@seb, translating the FORTRAN code to Mathematica would be quite the project... :) – 0x4A4D Oct 3 '12 at 16:23
2  
No, it's really quite easy if you look at this SO question :) It just boils down to defining a piecewise function. I was tempted to do it but I'm quite busy atm. – sebhofer Oct 3 '12 at 16:33
@J.M. having had experience in translating FORTRAN to Mathematica, it isn't bad. All the constructs are present, including Label and Goto; it just takes a little time. Even better: that code is pretty clean, the code I translated was far from it. – rcollyer Oct 3 '12 at 16:39
2  
Or more compactly: ListLinePlot[{ColorData["VisibleSpectrum"][#] /. RGBColor -> Sequence} & /@ Range[380, 750] // Transpose, PlotStyle -> {Red, Green, Blue}] – rm -rf Oct 3 '12 at 21:58
show 10 more comments

I just had a look at the colours as they are produced on my screen. I have been working with lasers for many (30+) years and can assure you that a 591nm laser line is fairly yellow, around 635nm is fairly red and 488nm appears as cyan, which resembles the colours of the disks well. Are you sure you are not confusing the wavelength of the maximum of black body radiation and its apparent colour with that of single lines? A perfect match of the numbers is not required but their ratios should be close.

With[{colors = {
    {Yellow, ColorData["VisibleSpectrum"][591]}, 
    {Cyan, ColorData["VisibleSpectrum"][488]}, 
    {Red, ColorData["VisibleSpectrum"][635]}}
    },
    ({#, Graphics[{#, Disk[]}] & /@ #} & /@ colors)~Flatten~1 // Grid
]

enter image description here

share|improve this answer
4  
“which resembles the colours of the disks well” — looking at your examples, I would actually say it does not match well at all. – F'x Oct 6 '12 at 13:35
1  
I agree with you; the 488 and 635nm images definitely look quite close to correct. What laser operates at 591nm? I've never used a yellow laser myself except as a by-product (idler wave of an OPO) of producing light around 430nm. – Oleksandr R. Oct 8 '12 at 9:24
2  
@F'x the proper comparison is not with the approximate descriptions but with the laser lines themselves. I'm pretty sure Ernst just included the discs on the LHS for the benefit of people who don't often work with lasers. – Oleksandr R. Oct 8 '12 at 9:28
2  
Of course it is only a proper comparison with a laser if the monitor is properly calibrated. For example, if his monitor is set to a lower colour temperature than 6500K, then a colour given in sRGB will look more "red shifted". However, I've now looked in the Mathematica documentation what RGB model Mathematica uses, and it doesn't seem to say anywhere; it's actually just an assumption that it uses sRGB. Of course, the exact RGB values corresponding to frequencies depend on the exact RGB model used. If it is really not documented, the RGB values for a given frequency are not well defined. – celtschk Oct 8 '12 at 12:26

That's a good question. There does seem to be a considerable discrepancy versus the 1931 CIE diagram:

GraphicsGrid @ List @ Table[
   Graphics @ {ColorData["VisibleSpectrum"][i], Disk[], White, Text[i]},
   {i, 380, 700, 10}
]

Mathematica graphics

enter image description here

Perhaps there was a miscalculation made in reducing the very large CIE color space values to sRGB triplets? sRGB, the standard display space, is the inset triangle below:

enter image description here

share|improve this answer
I was about to ask you if you created the diagrams yourself... than I took a look at wikipedia :) – sebhofer Oct 3 '12 at 14:54
@sebhofer No, I'm not that knowledgeable in the subject. – Mr.Wizard Oct 3 '12 at 14:55
1  
@seb: it should not be too hard to reproduce these diagrams in Mathematica, tho. :) – 0x4A4D Oct 3 '12 at 15:38
1  
@J.M. the tricky part is the tick marks along the surface of the region. – rcollyer Oct 3 '12 at 15:56
@J.M. I suspected that much but I was to timid to ask for it directly ;) – sebhofer Oct 3 '12 at 15:59

This is a bug (or an imperfection) of ColorData["VisibleSpectrum"].

Others have delved into its root, but in my answer I simply will make it clear by a comparison with an experimental, known single wavelength color[1]: sodium’s D-line at 589.0 nm.

Here is Mathematica’s idea of the color of this wavelength, using default settings (no color profile conversion applied, default MMA settings on my MacBook Pro, Mac OS X 10.8.2):

enter image description here

Anyone who has observed the sodium D-line during as a student will know that it doesn't have that greenish hue seen above. Now, here are spectroscopic observations of this same color, for those who have never seen it:

In conclusion: sure, color conversions are tricky… but here, Mathematica is well outside the margin of error :)

 

 

 


[1] Well, almost single color… the two lines are not that far apart.

share|improve this answer
Nice! Did you take those interferograms yourself? – 0x4A4D Oct 6 '12 at 13:53
@J.M. no, I did not (links are given in my answer)… I have set up these two types of interferometers in the past, but I never took pictures. Also, once you have the Michelson set up, it is much more beautiful to gaze at white light fringes than monochrome ones :) – F'x Oct 6 '12 at 13:58
1  
Perhaps I'm missing your point, but comparison with digital photographs made using the Na D-line is not going to give meaningful results; one should compare instead with actual sodium light. I tend to agree with Ernst; Mathematica's idea of what 514 or 532nm radiation look like is quite close to what they really do look like from a laser (less saturated in the former case, admittedly, but the sRGB color space is missing a huge chunk in this region, so that's not too surprising). – Oleksandr R. Oct 8 '12 at 9:11
@OleksandrR. I agree: the physical observation with one's eyes are the point I am trying to make, and digital photographs are only here to help as a comparison. But, I can tell from experience that the sodium D-line is not greenish at all, and very unlike Mathematica’s appearance on my screen. The images are much closer, proving that (for this particular wavelength), it's not so much a limitation of the sRGB color space. – F'x Oct 8 '12 at 9:25
Human perception of yellowish colors changes quite strongly with intensity, and sodium lights are typically quite bright. I agree that there is no green tinge to the Na D-line, but I'm not sure that Mathematica's representation of it looks all that greenish either. So far I'm not convinced as far as the yellow goes, but the other colors seem okay. – Oleksandr R. Oct 8 '12 at 9:37

The code in the article linked by Alexey produces something similar to this (gradient plot inspired by J.M.'s comment) :

rgb enter image description here

Note though that the description of the code does not seem consistent too me, so I had to change it in some places to get this result. Still I hope that I transcribed it more or less correctly. (I wouldn't use this for scientific purposes though!)

The code that creates the above figure is given below.

rgbSpec[x_] := 
RGBColor@@Piecewise[{
 {{19/100 + 19/3000 (410 - x), 0, 1 - 6/300 (410 - x)}, 380 <= x < 410}, 
 {{19/3000 (440 - x), 0, 1}, 410 <= x < 440},
 {{0, 1 - (490 - x)/50, 1}, 440 <= x < 490},
 {{0, 1, (510 - x)/20}, 490 <= x < 510},
 {{1 - (580 - x)/70, 1, 0},510 <= x < 580},
 {{1, (640 - x)/60, 0}, 580 <= x < 640},
 {{1, 0, 0}, 640 <= x < 700},
 {{35/100 + 65/8000 (780 - x), 0, 0}, 700 <= x <= 780}}]

(*rgb components*)
Plot[{rgbSpec[x][[1]], rgbSpec[x][[2]], rgbSpec[x][[3]]}, {x,380,780}, PlotStyle -> {Red, Green, Blue}, PlotRange -> All, Frame -> True]

(*gradient plot*)
DensityPlot[x, {x, 380, 780}, {y, 0, 1}, ColorFunction -> (rgbSpec[#] &), ColorFunctionScaling -> False,AspectRatio -> 1/10, FrameTicks -> {{None, None}, {Automatic, None}},Frame -> Automatic, PlotRangePadding -> None]

(If someone actually bothers to check, feel free to correct any mistakes!)

share|improve this answer
4  
Here's a compact version: rgbSpec[x_] := Blend[{{0, RGBColor[19/50, 0, 2/5]}, {3/40, RGBColor[19/100, 0, 1]}, {3/20, Blue}, {11/40, Cyan}, {13/40, Green}, {1/2, Yellow}, {13/20, Red}, {4/5, Red}, {1, RGBColor[7/20, 0, 0]}}, Rescale[x, {380, 780}]]. Here is a gradient plot of the proposed color scheme. – 0x4A4D Oct 5 '12 at 11:37
1  
+1 but please include the code that produces the plot shown, just for completeness. – Mr.Wizard Oct 5 '12 at 11:37
1  
@Mr.Wizard sorry for that... edited – sebhofer Oct 5 '12 at 12:10
@J.M. definitely a nicer way to do it! – sebhofer Oct 5 '12 at 12:10

If you look at the interval 570-590 nm, you will clearly see that it looks green at < 580 nm. It is just a problem of what we call "yellow".

share|improve this answer
2  
On this web site it definitely doesn't. Also, see the answer by Mr.Wizard. – celtschk Oct 3 '12 at 14:58
1  
@celtschk You're right. Looks like a bug now to me (same on wolframalpha). Also, nice demo with proper color spaces. – swish Oct 3 '12 at 15:46

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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