# How to draw a color square from a spectral distribution?

I need to draw a simple square filled with a flat uniform color, from a given spectral function. The color should simulate as close as possible what an human eye/brain would see, if the light intensity was defined as an integral of a simple function : $$\tag{1} f(\omega, \alpha, \kappa) = \kappa \, \omega^{\alpha},$$ where $\alpha \ge 0$ is a parameter and $0 \le \omega \le \omega_{\text{max}}$. Here, $\omega \equiv 2 \pi c /\lambda$ is the angular frequency of light and the minimal wavelength $\lambda_{\text{min}} \le 700 \, \text{nm}$ is another parameter that should be at least in the visible spectrum. $\kappa$ is a parameter that defines the whole intensity level of light, so $\kappa = 0$ should give black and $\kappa = \kappa_{\text{max}}$ should give a saturated color. The light intensity is defined as this : $$\tag{2} I(\alpha, \kappa, \lambda_{\text{min}}) = \int_0^{2\pi c/\lambda_{\text{min}}} f(\omega, \alpha, \kappa) \, d\omega.$$ I'm not a specialist on the eye/cones and color perception, but I guess that I need to call three "color" functions $r(\omega)$, $g(\omega)$ and $b(\omega)$ (the cones sensibility in the eye ?) to define the RGB values of my color, something like this (I'm not even sure this is necessary, with Mathematica, since it may be built-in somehow) : \begin{aligned} R(\alpha, \kappa, \omega_{\text{max}}) &= \frac{\int_0^{\omega_{\text{max}}} r(\omega) \, f(\omega, \alpha, \kappa) \, d\omega}{\int_0^{\omega_{\text{max}}} r(\omega) \, d\omega}, \\[12pt] G(\alpha, \kappa, \omega_{\text{max}}) &= \frac{\int_0^{\omega_{\text{max}}} g(\omega) \, f(\omega, \alpha, \kappa) \, d\omega}{\int_0^{\omega_{\text{max}}} g(\omega) \, d\omega}, \\[12pt] B(\alpha, \kappa, \omega_{\text{max}}) &= \frac{\int_0^{\omega_{\text{max}}} b(\omega) \, f(\omega, \alpha, \kappa) \, d\omega}{\int_0^{\omega_{\text{max}}} b(\omega) \, d\omega}. \end{aligned} Then Mathematica would use the values of $R(\alpha, \kappa, \omega_{\text{max}})$, $G(\alpha, \kappa, \omega_{\text{max}})$, $B(\alpha, \kappa, \omega_{\text{max}})$ to draw the color filled square.

Any idea about how to achieve this ?

I'm posting a working "Manipulate" code to show a very partial solution. Currently, it is highly approximate and it needs to be fixed in some way.

Clear["Global*"]  (* removes all definitions *)

c = 299792458;  (* velocity of light *)
nm = 10^(-9);  (* nanometer *)

(* normalized distribution of frequencies : *)

f[ω_, d_, κ_, λ_] := κ If[ω <=  2Pi c/(λ nm), ω^(d/2), 0]/Integrate[u^(d/2), {u, 0, 2Pi c/(λ nm)}]

(* very approximate Red, Green, Blue channels : *)

Rcolor[d_, κ_, λ_] := f[2Pi c/(700 nm), d, κ, λ]2Pi c/(λ nm)
Gcolor[d_, κ_, λ_] := f[2Pi c/(550 nm), d, κ, λ]2Pi c/(λ nm)
Bcolor[d_, κ_, λ_] := f[2Pi c/(450 nm), d, κ, λ]2Pi c/(λ nm)

(* the full color : *)

color[d_, κ_, λ_] := RGBColor[
If[Rcolor[d, κ, λ] < 1, Rcolor[d, κ, λ], 1],
If[Gcolor[d, κ, λ] < 1, Gcolor[d, κ, λ], 1],
If[Bcolor[d, κ, λ] < 1, Bcolor[d, κ, λ], 1]
]

(* the manipulate code to show a color square with adjustable parameters : *)

Manipulate[
If[d < 0 || d > 6 || Not[NumericQ[d]], d = 4];
If[κ < 0 || κ > 1 || Not[NumericQ[κ]], κ = 0.5];
If[λ < 100 || λ > 700 || Not[NumericQ[λ]], λ = 400];
Show[
Graphics[{color[d, κ, λ], Rectangle[]}],
ImageSize -> 400
],
{{d, 4, Style["d", 10]}, 0, 6, 0.01,
ImageSize -> Medium,
Appearance -> {"Labeled", "Closed"}
},
{{κ, 0.5, Style["Intensity", 10]}, 0, 1, 0.01,
ImageSize -> Medium,
Appearance -> {"Labeled", "Closed"}
},
{{λ, 400, Style["λ (nm)", 10]}, 100, 700, 0.01,
ImageSize -> Medium,
Appearance -> {"Labeled", "Closed"}
},
ControlPlacement -> Bottom,
FrameMargins -> None,
FrameLabel ->  {None, None,
Style["Deep space color", Bold, 14, FontFamily -> "Helvetica"]}
]
`

In this code, the color "cones" are peaked at some arbitrary values : Red = 700 nm, Green = 550 nm and Blue = 450 nm (all arbitrary values).

How can I improve that code to get a more realistic color output ?

EDIT : I just found a similar question here, which can be usefull : Convert spectral distribution to RGB color. However, my question is specific with the spectral function and its parameters, and I'm unable to understand and adapt the answers from that question. The answers don't work at all on my system (Mathematica 7.0 on OS X).

• Ouch, version 7 is pretty outdated. A lot of new a useful functionality had been added since, it may be tricky for someone used to modern Wolfram Language methods to immediately offer something to help.
– ktm
Oct 28 '16 at 3:22
• Well then, there is surely a trick to get the approximate color of the distribution. It may be enough for me, I don't need something exact.
– Cham
Oct 28 '16 at 13:12
• "The answers don't work at all on my system" - even the functions here and here don't work for you? Dec 28 '16 at 11:59
• The correct procedure for this problem is as follows: Choose an illuminant for the spectral power distribution values. D50 is what is used in my industry and what I use for illuminant. Then convert spectral power to CIEXYZ, then from there to RGB based on your chosen RGB color space. More than likely its your monitor. Jan 30 '17 at 20:10