A program/Java applet that will show me the color of a wavelength?

Now that I’ve started working in a lab over the summer I’ve run across a few things such as this:

“After staining, gels are destained and visualized using a standard UV light box, or any of a variety of laser-based gel scanners. The excitation wavelengths are 300 and 480 nm and the emission wavelength is 618 nm.”

Of course, it might be awesome to know, ya’ know, what 618 nm wavelength light actually looks like in terms of color. My Google-fu has provided me with many links to spectrums that generally mark where different visible colors lie along the spectrum such as this:

http://en.wikipedia.org/wiki/Color

However, what I would really like is some sort of website with a Java applett or even a small download where I could type in a wavelength or even three or four distinct wavelengths at varrying intensity and the program would spit out a nice, big color “swatch” for me to look at and know what 618 nm light actually looks like.

So, Dopers, where can I find something like that?

First, it’s important to note that the spectrum of pure monochromatic colors and the colorspaces commonly used for computer monitors (RGB, etc.) are not really convertible: in each color space there are colors which are perceived differently from any color in the other (as seen in CIE charts like this one). You can approximate the spectrum with some mapping from the monochromatic colors to (r,g,b) values, as is done in this Fortran code.

Here is a quick-and-dirty DHTML program to color the HTML background with a color approximating the given wavelength (approximately implementing the Fortran code linked above; I didn’t bother with gamma). setcolor() is the function that does the conversion; it will obviously need to be tweaked for each individual monitor-eye pair to give really good results. Tested on Mozilla only.


<html>
<head>
<title>Spectral colors</title>
<script>
var reg;
var cin;
var cout;
function init() {
  reg = document.getElementById("region");
  cin = document.getElementById("input");
  cout= document.getElementById("output");
}

function tohex( x ) {
  x = Math.floor(x*255);
  x = x.toString(16);
  if ( x.length == 1 ) x = "0"+x;
  return x;
}

function setcolor( ) { // implement Dan Bruton's wavelength->RGB mapping
  var nm, r, g, b, rgb, s;

  nm = cin.value;
  if ( nm < 380 || nm > 780 ) { cout.value = "Not in [380,780] nm."; return; }
  else if ( nm < 440 ) { r = (440-nm)/(440-380); g = 0; b = 1; }
  else if ( nm < 490 ) { r = 0; g = (nm-440)/(490-440); b = 1; }
  else if ( nm < 510 ) { r = 0; g = 1; b = (510-nm)/(510-490); }
  else if ( nm < 580 ) { r = (nm-510)/(580-510); g = 1; b = 0; }
  else if ( nm < 645 ) { r = 1; g = (645-nm)/(645-580); b = 0; }
  else { /* nm <=780 */  r = 1; g = 0; b = 0; }

  if ( nm > 700 ) { s = 0.3 + 0.7*(780-nm)/(780-700); r *= s; g *= s; b *= s; }
  if ( nm < 420 ) { s = 0.3 + 0.7*(nm-380)/(420-780); r *= s; g *= s; b *= s; }

  rgb = tohex(r) + tohex(g) + tohex(b);
  cout.value = rgb;
  reg.style.backgroundColor = "#" + rgb;
}
</script>
</head>
<body id="region" style="color: #fff; background-color: #000" onload="init()">
<table>
<tr><td>Input wavelength in nm:</td>
    <td><input id="input" type=text onchange="setcolor()"></td></tr>
<tr><td>Output color (#RRGGBB):</td>
    <td><input id="output" type=text readonly></td></tr>
</table>
</body>
</html>

You could easily modify this code to accept input via HTML query strings, to have multiple colored regions, etc.

Well, that was maybe a bad choice of CIE chart, since it doesn’t show a sample RGB colorspace. Here’s one that shows some sample RGB color triangles.

Well, Omphalo, I say good enough for government work. It’s not perfect but it gives me a very good idea of what color to look for and I do appreciate the effort.

Thank you again,
Omphalo

Ah, damn it all.

My own inclination and talent towards executing such programming is now painfully on display.

No slight, but there is a bug in the code I think. Check out the difference in display between 419 and 420 wavelink inputs.

Yeah,

if ( nm < 420 ) { s = 0.3 + 0.7*(nm-380)/(420-780); r *= s; g *= s; b *= s; }

should be

if ( nm < 420 ) { s = 0.3 + 0.7*(nm-380)/(420-380); r *= s; g *= s; b *= s; }

Oops. Thanks.