Map value to color scale

2020-04-07 04:22发布

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 n to a color that represents its value.

An example and my solution so far is to normalize the values based on the min and max and then assign them to hex color 0 for the lowest and 255 for the highest. This of course limits my self to the grey scale. Here is the code:

$color = ($value / $max) * 255    // (min is zero)

But how to do this if the values should go from blue to red for instance? Is there any common libraries or tools that can solve this? So far I haven't been able to locate any.

标签: php colors
5条回答
劳资没心,怎么记你
2楼-- · 2020-04-07 04:34

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.

Demo

Gist with the code: Click here

查看更多
孤傲高冷的网名
3楼-- · 2020-04-07 04:39

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:

  1. A predefined color index, e.g. $coloridx=array(0=>'#FFFFFF',1=>'#FFEE00',...);
  2. Any algorithm, e.g. linear gradient, which is basically an iterations based adaption of all three RGB channels (R = red, G = green, B = blue).
  3. A combination of both, which usually puts the result of any complex algorithm to the color index and then goes from there.

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.

查看更多
beautiful°
4楼-- · 2020-04-07 04:40

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

查看更多
smile是对你的礼貌
5楼-- · 2020-04-07 04:53

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>';
    }
查看更多
劳资没心,怎么记你
6楼-- · 2020-04-07 04:57

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);
}
查看更多
登录 后发表回答