title: Star B-V color index to apparent RGB color
body: <p>I'm trying to convert a star's <a href="http://en.wikipedia.org/wiki/B-V_colour" rel="noreferrer">B-V color index</a> to an apparent RGB color. Besides look up tables and color ramps, it seems like there's no well known algorithm for doing this.</p>
  
  <h2>What's a B-V color index?</h2>
  
  <p>It's a number astronomers assign to a star to indicate its apparent color. Hot stars (low B-V) are blue/purple and cool stars (high B-V) are red with those white/orange stars in between.</p>
  
  <h2>Initial algorithm</h2>
  
  <h3>B-V to Kelvin</h3>
  
  <p><img src="https://i.stack.imgur.com/m3GOe.png" alt="enter image description here"></p>
  
  <pre><code>var t = 4600 * ((1 / ((0.92 * bv) + 1.7)) +(1 / ((0.92 * bv) + 0.62)) );
  </code></pre>
  
  <h3>Kelvin to xyY</h3>
  
  <p>If you model a star as a blackbody, then you can use a numerical approximation of the <a href="http://en.wikipedia.org/wiki/Planckian_locus" rel="noreferrer">Planckian locus</a> to compute the xy coordinates (CIE chromaticity)</p>
  
  <p><img src="https://i.stack.imgur.com/bhofh.png" alt="enter image description here"></p>
  
  <p><img src="https://i.stack.imgur.com/Z9t1a.png" alt="enter image description here"></p>
  
  <p><img src="https://i.stack.imgur.com/ZZdwQ.png" alt="enter image description here"></p>
  
  <pre><code>// t to xyY
  var x, y = 0;
  
  if (t&gt;=1667 &amp;&amp; t&lt;=4000) {
    x = ((-0.2661239 * Math.pow(10,9)) / Math.pow(t,3)) + ((-0.2343580 * Math.pow(10,6)) / Math.pow(t,2)) + ((0.8776956 * Math.pow(10,3)) / t) + 0.179910;
  } else if (t &gt; 4000 &amp;&amp; t &lt;= 25000) {
    x = ((-3.0258469 * Math.pow(10,9)) / Math.pow(t,3)) + ((2.1070379 * Math.pow(10,6)) / Math.pow(t,2)) + ((0.2226347 * Math.pow(10,3)) / t) + 0.240390;
  }
  
  if (t &gt;= 1667 &amp;&amp; t &lt;= 2222) {
    y = -1.1063814 * Math.pow(x,3) - 1.34811020 * Math.pow(x,2) + 2.18555832 * x - 0.20219683;
  } else if (t &gt; 2222 &amp;&amp; t &lt;= 4000) {
    y = -0.9549476 * Math.pow(x,3) - 1.37418593 * Math.pow(x,2) + 2.09137015 * x - 0.16748867;
  } else if (t &gt; 4000 &amp;&amp; t &lt;= 25000) {
    y = 3.0817580 * Math.pow(x,3) - 5.87338670 * Math.pow(x,2) + 3.75112997 * x - 0.37001483;
  }
  </code></pre>
  
  <h3><a href="http://en.wikipedia.org/wiki/XYZ_color_space" rel="noreferrer">xyY to XYZ (Y = 1)</a></h3>
  
  <p><img src="https://i.stack.imgur.com/A5MgD.png" alt="enter image description here"></p>
  
  <p><img src="https://i.stack.imgur.com/WPX77.png" alt="enter image description here"></p>
  
  <pre><code>// xyY to XYZ, Y = 1
  var Y = (y == 0)? 0 : 1;
  var X = (y == 0)? 0 : (x * Y) / y;
  var Z = (y == 0)? 0 : ((1 - x - y) * Y) / y;
  </code></pre>
  
  <h3><a href="http://en.wikipedia.org/wiki/XYZ_color_space" rel="noreferrer">XYZ to RGB</a></h3>
  
  <p><img src="https://i.stack.imgur.com/6mNfX.png" alt="enter image description here"></p>
  
  <pre><code>var r = 0.41847 * X - 0.15866 * Y - 0.082835 * Z;
  var g = -0.091169 * X + 0.25243 * Y + 0.015708 * Z;
  var b = 0.00092090 * X - 0.0025498 * Y + 0.17860 * Z;
  </code></pre>
  
  <h2>Question</h2>
  
  <p>I ran this algorithm with the B-V color indexes: 1.2, 1.0, 0.59, 0.0, -0.29. This is what I got as output. </p>
  
  <p><img src="https://i.stack.imgur.com/C1RCl.png" alt="enter image description here"></p>
  
  <p><strong>Why did I get this strange output?</strong> Hot stars are bluish but cold stars are brownish and there doesn't seem to be white/orange intermediate stars.</p>
  
  <h2>Update</h2>
  
  <p>Following on a comment by <a href="https://stackoverflow.com/users/137065/ozan">Ozan</a>, it seemed like I was using a wrong matrix to convert XYZ to RGB. Since sRGB is the default color space on the web (or is it?), I'm now using the correct matrix followed by a gamma correction function (<code>a = 0.055</code>). </p>
  
  <p><img src="https://i.stack.imgur.com/IoeK5.png" alt="enter image description here"></p>
  
  <p><img src="https://i.stack.imgur.com/WPHG4.png" alt="enter image description here"></p>
  
  <p>I now get this nice color ramp,</p>
  
  <p><img src="https://i.stack.imgur.com/3EuKa.png" alt="enter image description here"></p>
  
  <p>but there's still no red/violet at the extremities.</p>
  
  <h2>Demo</h2>
  
  <p>There's also a <a href="http://jsfiddle.net/AkjDw/1/" rel="noreferrer">fiddle</a> now that you can play with.</p>
  
  <h2>Update 2</h2>
  
  <p>If use a gamma of 0.5 and extend the range of B-V color indexes to be from 4.7 to -0.5, I get red at one extreme but still no violet. Here's the updated <a href="http://jsfiddle.net/AkjDw/2/" rel="noreferrer">fiddle</a>.</p>
  
  <p><img src="https://i.stack.imgur.com/Q4LCS.png" alt="enter image description here"></p>