Since ColorData["VisibleSpectrum"] is wrong, I would like to have a more accurate function to use.
Can this information be extracted from Mathematica itself?
Answer
Notice:
Simon Woods did just this months ago for an answer I missed:
It seems that it can. By spelunking ChromaticityPlot I found:
Image`ColorOperationsDump`$wavelengths
Image`ColorOperationsDump`tris
These are a list of wavelengths and their corresponding XYZ color values used by this plot command:
ChromaticityPlot["sRGB", Appearance -> {"VisibleSpectrum", "Wavelengths" -> True}]

We can therefore use them to generate a new color function:
ChromaticityPlot; (* pre-load internals *)
newVisibleSpectrum =
With[
{colors =
{Image`ColorOperationsDump`$wavelengths,
XYZColor @@@ Image`ColorOperationsDump`tris}\[Transpose]},
Blend[colors, #] &
];
A comparison with the old function:
ArrayPlot[
{Range[385, 745]},
ImageSize -> 400,
AspectRatio -> 0.1,
ColorFunctionScaling -> False,
ColorFunction -> #
] & /@
{"VisibleSpectrum", newVisibleSpectrum} // Column

589nm is now the bright sodium yellow that it should be:
Graphics[{newVisibleSpectrum @ 589, Disk[]}]

If you wish to integrate this into ColorData see:
As requested by J.M. red-green-blue plots for each function:
old = List @@@ Array[ColorData["VisibleSpectrum"], 361, 385];
new = List @@@ ColorConvert[Array[newVisibleSpectrum, 361, 385], "RGB"];
ListLinePlot[Transpose @ #,
PlotStyle -> {Red, Green, Blue},
DataRange -> {385, 745}
] & /@ {old, new}

Clipping occurs during conversion to screen RGB; the newVisibleSpectrum function actually produces unclipped XYZColor data. For example projected over gray:
newVSgray =
With[{colors =
Array[{#, Blend[{newVisibleSpectrum@#, ColorConvert[GrayLevel[.66], "XYZ"]},
0.715]} &, 361, 385]}, Blend[colors, #] &];
ListLinePlot[
List @@@ ColorConvert[Array[newVSgray, 361, 385], "RGB"] // Transpose,
PlotStyle -> {Red, Green, Blue}, DataRange -> {385, 745}, ImageSize -> 400]

Which corresponds to the plot:
ArrayPlot[{Range[385, 745]}, ImageSize -> 400, AspectRatio -> 0.1,
ColorFunctionScaling -> False, ColorFunction -> newVSgray,
Background -> GrayLevel[0.567]]

cf. "VisibleSpectrum" similarly over gray blended in XYZColor and RGBColor respectively:


Note that neither rendering of this spectrum has the vibrancy of newVisibleSpectrum.
Comments
Post a Comment