I have a list of values which should be plotted to a map with a certain color.
The plotting to the map is already done, but I need to figure out a way to map the value
Colors values are representations. Numeric colors as well as hexadecimal colors. A "not grayscale" color contains at least 2 different informations: Red value, green value or blue values may be different. Performing operation on its representation gives wrong result. The 'Mapping" must then be performed on each pieces of information. You need to extract red, green and blue values, perform the mapping seperatly, then build the representation of the result color. Here is a quick helper that use a "min color" and "max color", performs mapping on red, green and blue values, according to the "n" value you need to work with, then return the result color in hexadecimal string. It works for any colors or gray scale color as well.
function linear_color($from, $to, $ratio) {
// normalize ralio
$ratio = $ratio<0?0:($ratio>1?1:$ratio);
// unsure colors are numeric values
if(!is_numeric($from))$from=hexdec($from);
if(!is_numeric($to))$to=hexdec($to);
$rf = 0xFF & ($from >> 0x10);
$gf = 0xFF & ($from >> 0x8);
$bf = 0xFF & $from;
$rt = 0xFF & ($to >> 0x10);
$gt = 0xFF & ($to >> 0x8);
$bt = 0xFF & $to;
return str_pad( dechex(($bf + (($bt-$bf)*$ratio)) + ($gf + (($gt-$gf)*$ratio) << 0x8) + ($rf + (($rt-$rf)*$ratio) << 0x10)), 6,'0',STR_PAD_LEFT);
}
Just specify 2 colors as numeric value or hexadecimal string (without hash!) like this :
$color_from = hexdec('c2c2c2');
$color_to = hexdec('1eb02b');
for($i=-0.2; $i<=1.3; $i+=0.04){
echo '<div style="background-color: #';
echo linear_color($color_from, $color_to, $i);
echo '">';
echo 'Result color when n = <strong>'.$i.'</strong>';
echo '</div>';
}
The other answer was very usefull. I decided to use JS as it reduces server load. The requirements also changed. The bar has to go from Red to white in the middle and then from white to yellow. And if the value is 0 it should be black. Here is my code for anyone who ever encounters a similar situation.
var normalize_base = 2*255;
var no_con_color = "black";
function decimalToHex(d, padding) {
var hex = Number(d).toString(16);
padding = typeof (padding) === "undefined" || padding === null ? padding = 2 : padding;
while (hex.length < padding) {
hex = "0" + hex;
}
return hex;
}
function normalize(max, min, value)
{
var normalized = (value - min) / (max - min) ;
return Math.floor(normalized * normalize_base);
}
function value2Color(value)
{
if(value <= 0 || value == undefined)
{
return no_con_color;
}
var g = 0;
var b = 0;
var r = 0;
if(value < 255)
{
r = 255;
g = value;
b = value;
} else {
r = (2*255) - value;
g = 255;
b = (2*255) - value;
}
return "#" + decimalToHex(r) + decimalToHex(g) + decimalToHex(b);
}
This is one-function-only code to convert any number from any given range (let's say [0,20]) to particular color where 0 is red, 10 is yellow, 20 is green. You can use any colors and even use combination of 4 colors, so it's red - yellow - green - blue.
See the end of the gist file, where this function is used.
Gist with the code: Click here
There might be libs to do that. However let's get a short warm up into the general principles. In general you have following options:
$coloridx=array(0=>'#FFFFFF',1=>'#FFEE00',...);
If you include algorithms in your considerations you must understand that there is no true
or false
. It all depends on what you would like to implement. There might be occasions where it makes sense to render variations of green into n=0..10
and then have red to black in everything beyond n>10
. Caps and multipliers help to set accents. Things like that.
One way of implementing a linear gradient would be:
function lineargradient($ra,$ga,$ba,$rz,$gz,$bz,$iterationnr) {
$colorindex = array();
for($iterationc=1; $iterationc<=$iterationnr; $iterationc++) {
$iterationdiff = $iterationnr-$iterationc;
$colorindex[] = '#'.
dechex(intval((($ra*$iterationc)+($rz*$iterationdiff))/$iterationnr)).
dechex(intval((($ga*$iterationc)+($gz*$iterationdiff))/$iterationnr)).
dechex(intval((($ba*$iterationc)+($bz*$iterationdiff))/$iterationnr));
}
return $colorindex;
}
$colorindex = lineargradient(
100, 0, 0, // rgb of the start color
0, 255, 255, // rgb of the end color
256 // number of colors in your linear gradient
);
$color = $colorindex[$value];
I UPDATED the code to add dechex, which feeds back on the comments.
There is I2UI for this.
<div data-i2="color:['#404040','#00FF21']">
<span data-i2="rate:1">A</span>
<span data-i2="rate:2">B</span>
<span data-i2="rate:3">C</span>
<span data-i2="rate:4">D</span>
<span data-i2="rate:5">E</span>
</div>
There is a color range: from "Gray" - to "Green". The span element that has lowest rate value get the "Gray" color, the element with the biggest rate get "Green" color.
Thus, the span that are between edges get the color that has direct ratio to its rate.
Also, call JavaScript i2.emph() after the previous HTML have been loaded.
See demo