View on GitHub

color-map-J-coupling

Color map for NMR homonuclear coupling constants.

Color map for J coupling

This color map was designed for J-graphs and other color-coded representation of NMR J(H,H) ranging from 0 to 20 Hz.

It was chosen order to provide a large color contrast for values that are particularily significant (small, about 7.0 and about 12 Hz).

J Black background White background
Hz RGB (0-1) RGB (0-1)
0 (0 1 1) (0 1 1)
2 (0 1 0) (0 1 0)
4 (1 1 0) (0.8 0.8 0)
6 (1 0.5 0) (0.9 0.4 0)
8 (1 0 0) (1 0 0)
10 (1 0 0.5) (1 0 0.5)
12 (1 0 1) (1 0 1)
14 (0.5 0 0.9) (0.5 0 1)
16 (0.2 0.2 1) (0 0 1)
18 (0.4 0.4 0.5) (0 0 0.5)
20 (1 1 1) (0 0 0)

Convert J value into (R, G, B) values (0 - 1). In C++

// input
const double Jcoupling = 7.1 ; // Hz

// Color maps. First color for 0 Hz, second color for 2 Hz, etc. up to 20 Hz
const double colormapWhiteBackground[] = {0, 1, 1, 0, 1, 0, 0.8, 0.8, 0, 0.9, 0.4, 0, 1, 0, 0, 1, 0, 0.5, 1, 0, 1, 0.5, 0, 1, 0, 0, 1, 0, 0, 0.5, 0, 0, 0,}; // for white background
const double colormap[] = {0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0.5, 0, 1, 0, 0, 1, 0, 0.5, 1, 0, 1, 0.5, 0, 0.9, 0.2, 0.2, 1, 0.4, 0.4, 0.5, 1, 1, 1,}; // for black background
   
const double JcouplingAbs = abs(Jcoupling) ; // Hz
int baseColorInt = floor(JcouplingAbs / 2.0); // -20 - 20.0 ->  0 - 9 
if (baseColorInt > 9) baseColorInt = 9; // baseColorInt 0 - 9
float adjust = (JcouplingAbs - 2 * baseColorInt) / 2.0; // normalized diff (0-1) for 2 Hz
if (adjust > 1.0) adjust = 1.0; // adjust 0 - 1.0
const int baseColorIndex =  3 * baseColorInt; // 3 because RGB

// Output
double colormap[] = {0, 0, 0};
// the loop is language dependent, lets drop it...
curColor[0] = colormap[baseColorIndex + 0] + adjust * (colormap[baseColorIndex + 3 + 0] - colormap[baseColorIndex + 0]);
curColor[1] = colormap[baseColorIndex + 1] + adjust * (colormap[baseColorIndex + 3 + 1] - colormap[baseColorIndex + 1]);
curColor[2] = colormap[baseColorIndex + 2] + adjust * (colormap[baseColorIndex + 3 + 2] - colormap[baseColorIndex + 2]);

const bool negExpVal = (Jcoupling < 0.0); // used to change line type for negative values.                   

Javascript version

export function getJColor(Jcoupling, darkmode) {
    // https://nmredatainitiative.github.io/color-map-J-coupling/
    // input
    // Color maps. First color for 0 Hz, second color for 2 Hz, etc. up to 20 Hz

    var colormap = [0, 1, 1, 0, 1, 0, 0.8, 0.8, 0, 0.9, 0.4, 0, 1, 0, 0, 1, 0, 0.5, 1, 0, 1, 0.5, 0, 1, 0, 0, 1, 0, 0, 0.5, 0, 0, 0]; // for white background
    if (darkmode) {
      colormap = [0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0.5, 0, 1, 0, 0, 1, 0, 0.5, 1, 0, 1, 0.5, 0, 0.9, 0.2, 0.2, 1, 0.4, 0.4, 0.5, 1, 1, 1]; // for black background
    }

    const JcouplingAbs = Math.abs(Jcoupling); // Hz
    var baseColorInt = Math.floor(JcouplingAbs / 2.0); // -20 - 20.0 ->  0 - 9 
    if (baseColorInt > 9) baseColorInt = 9; // baseColorInt 0 - 9
    var adjust = +(JcouplingAbs - 2.0 * baseColorInt) / 2.0; // normalized diff (0-1) for 2 Hz
    if (adjust > 1.0) adjust = 1.0; // adjust 0 - 1.0
    const baseColorIndex = 3 * baseColorInt; // 3 because RGB

    // the loop is language dependent, lets drop it...
    const r = Math.floor(+255.0 * (colormap[baseColorIndex + 0] + adjust * (colormap[baseColorIndex + 3 + 0] - colormap[baseColorIndex + 0])));
    const g = Math.floor(+255.0 * (colormap[baseColorIndex + 1] + adjust * (colormap[baseColorIndex + 3 + 1] - colormap[baseColorIndex + 1])));
    const b = Math.floor(+255.0 * (colormap[baseColorIndex + 2] + adjust * (colormap[baseColorIndex + 3 + 2] - colormap[baseColorIndex + 2])));

    //const negExpVal = (Jcoupling < 0.0); // used to change line type for negative values.                   

    return (["rgb(", r, ",", g, ",", b, ")"].join(""));
  }

Javascript version

export function getJColor(Jcoupling, darkmode) {
    // https://nmredatainitiative.github.io/color-map-J-coupling/
    // input
    // Color maps. First color for 0 Hz, second color for 2 Hz, etc. up to 20 Hz

    var colormap = [0, 1, 1, 0, 1, 0, 0.8, 0.8, 0, 0.9, 0.4, 0, 1, 0, 0, 1, 0, 0.5, 1, 0, 1, 0.5, 0, 1, 0, 0, 1, 0, 0, 0.5, 0, 0, 0]; // for white background
    if (darkmode) {
      colormap = [0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0.5, 0, 1, 0, 0, 1, 0, 0.5, 1, 0, 1, 0.5, 0, 0.9, 0.2, 0.2, 1, 0.4, 0.4, 0.5, 1, 1, 1]; // for black background
    }

    const JcouplingAbs = Math.abs(Jcoupling); // Hz
    var baseColorInt = Math.floor(JcouplingAbs / 2.0); // -20 - 20.0 ->  0 - 9 
    if (baseColorInt > 9) baseColorInt = 9; // baseColorInt 0 - 9
    var adjust = +(JcouplingAbs - 2.0 * baseColorInt) / 2.0; // normalized diff (0-1) for 2 Hz
    if (adjust > 1.0) adjust = 1.0; // adjust 0 - 1.0
    const baseColorIndex = 3 * baseColorInt; // 3 because RGB

    // the loop is language dependent, lets drop it...
    const r = Math.floor(+255.0 * (colormap[baseColorIndex + 0] + adjust * (colormap[baseColorIndex + 3 + 0] - colormap[baseColorIndex + 0])));
    const g = Math.floor(+255.0 * (colormap[baseColorIndex + 1] + adjust * (colormap[baseColorIndex + 3 + 1] - colormap[baseColorIndex + 1])));
    const b = Math.floor(+255.0 * (colormap[baseColorIndex + 2] + adjust * (colormap[baseColorIndex + 3 + 2] - colormap[baseColorIndex + 2])));

    //const negExpVal = (Jcoupling < 0.0); // used to change line type for negative values.                   

    return (["rgb(", r, ",", g, ",", b, ")"].join(""));
  }

Please make pull requests or raise issue to send us your code in other languages!