If I understood your question correctly, you don't really want a shape with a color gradient. What you really want is solid-color objects whose colors are determined by two parameters:
- The category (cat1, cat2 and cat3 in your example)
- A degree of coloration (the weights in column 3)
Furthermore, the colors in your example seem to follow a model where smaller numbers are nearer to white, larger numbers are nearer to black, and numbers in the middle are saturated colors. In terms of color space, this suggests something like the Hue, Saturation, Lightness color space, as depicted in this picture from Wikipedia:

To map this back to your example above, I suspect weights near 0.0 would be near the top of the double-cone, weights near 10.0 would be near the bottom of the double-cone, and the colors represented by your categories have a fixed hue and saturation (notionally near the equator of the double-cone) adjusted by these weights.
The following perl code converts an HSL color to RGB. It was adapted from this StackOverflow answer, which in turn was adapted from the Wikipedia page I linked above. This is only part of the necessary solution:
##
## Converts an HSL color value to RGB. Conversion formula
## adapted from http://en.wikipedia.org/wiki/HSL_color_space.
## Assumes h, s, and l are contained in the set [0, 1] and
## returns r, g, and b in the set [0, 255].
##
## @param Number h The hue
## @param Number s The saturation
## @param Number l The lightness
## @return Array The RGB representation
##
sub hsl_to_rgb
{
my ($h, $s, $l) = @_;
my ($r, $g, $b);
if ($s == 0)
{
$r = $g = $b = $l; ## achromatic
} else
{
sub hue2rgb
{
my ($p, $q, $t) = @_;
while ($t < 0) { $t += 1; }
while ($t > 1) { $t -= 1; }
if ($t < 1/6) { return $p + ($q - $p) * 6 * $t; }
if ($t < 1/2) { return $q; }
if ($t < 2/3) { return $p + ($q - $p) * (2/3 - $t) * 6; }
return $p;
}
my $q = $l < 0.5 ? $l * (1 + $s) : $l + $s - $l * $s;
my $p = 2 * $l - $q;
$r = hue2rgb($p, $q, $h + 1/3);
$g = hue2rgb($p, $q, $h);
$b = hue2rgb($p, $q, $h - 1/3);
}
return [ int($r * 255), int($g * 255), int($b * 255) ];
}
This function takes an HSL color in the form of, say, (0, 1.0, 0.5)
for pure red, and returns an RGB triplet of the form [ 255, 0, 0 ]
. That gives you one piece of the puzzle.
Based on what I can tell from your problem statement, you have a set of base colors that you can probably express in terms of hue and saturation, sorted by category. Something like this:
my %cat_colors =
( # Hue Saturation
cat1 => [ 0.00000, 1.00000 ], # Red
cat2 => [ 0.16667, 1.00000 ], # Yellow
cat3 => [ 0.33333, 1.00000 ], # Green
);
Update by OP: This is brilliant. For adding colors in more category, the 'hue' value can be checked in this website: http://www.color-hex.com/ . Note for example that this website state the HSL for red is : 0.00 1.00 0.50
.
Note: You'll definitely want to play with these colors. If you have Photoshop or some other tool that lets you see colors in terms of different color spaces, that may help you pick the "base" color for each category to be exactly what you want. For the hsl_to_rgb
code above, you'll want to scale the hue and saturation values to be in the range [0, 1].
Now how do we apply this to the weight parameter you gave above? It appears, as I said above, that it maps directly to the lightness parameter in HSL, with a weight of 0.0 mapping to white, and a weight of 10.0 mapping to black. (At least, to a first order, given your sketch, that seems like a good starting point.) In HSL, though, 1.0 is white and 0.0 is black. So to map weight to lightness, you need an expression like this:
$lightness = 1 - ($weight / 10);
You could wrap this in a function:
sub weight_to_light
{
return 1 - ($_[0] / 10);
}
The final piece in the equation is mapping the RGB returned by hsl_to_rgb
into something HTML can work with. That's actually pretty simple. The following short function converts the array of R,G,B values from hsl_to_rgb
into an HTML-ready hexadecimal string:
sub rgb_to_html_hex
{
return sprintf "#%.2X%.2X%.2X", @{ $_[0] };
}
So, putting it all together: If you want to produce a hash named %col4
given the details in %col2
and %col3
that contains the strings you'll need in HTML to color objects according to the coloring model above, you need the two functions above, the %cat_colors
mapping, and some code like this:
my %col4;
foreach my $key (keys %col2)
{
foreach my $i ( 0 .. scalar( @{ $col2{$key} } ) - 1 )
{
my $base_color = $cat_colors{ $col2{$key}->[$i] };
my $rgb_color = hsl_to_rgb( @$base_color,
weight_to_light( $col3{$key}->[$i] ) );
my $html_color = rgb_to_html_hex( $rgb_color );
$col4{$key}->[$i] = $html_color;
}
}
Once you've generated %col4
, you can use the resulting HTML strings to color individual entities. My modern HTML is a bit rusty, but I know that constructs such as <FONT COLOR="#xxxxxx">
worked at one time, and may still yet work. I leave it to you to construct syntactically valid and sufficiently modern HTML from the values computed.
Now, you must admit, I've made some bold assumptions about the problem you're trying to solve and how it needs to be solved. I think, though, I'm in the general ballpark. If you have questions, feel free to leave comments.
And... for your cut-and-paste convenience, here's a quick test program where I copied all the above bits, along with your sample data set into a standalone, testable perl program. Enjoy! The last two lines use YAML::XS to dump out the computed values for %col4
so I could see if they were plausible.
#!/usr/bin/perl -w
use Modern::Perl;
##
## Converts an HSL color value to RGB. Conversion formula
## adapted from http://en.wikipedia.org/wiki/HSL_color_space.
## Assumes h, s, and l are contained in the set [0, 1] and
## returns r, g, and b in the set [0, 255].
##
## @param Number h The hue
## @param Number s The saturation
## @param Number l The lightness
## @return Array The RGB representation
##
sub hsl_to_rgb
{
my ($h, $s, $l) = @_;
my ($r, $g, $b);
if ($s == 0)
{
$r = $g = $b = $l; ## achromatic
} else
{
sub hue2rgb
{
my ($p, $q, $t) = @_;
while ($t < 0) { $t += 1; }
while ($t > 1) { $t -= 1; }
if ($t < 1/6) { return $p + ($q - $p) * 6 * $t; }
if ($t < 1/2) { return $q; }
if ($t < 2/3) { return $p + ($q - $p) * (2/3 - $t) * 6; }
return $p;
}
my $q = $l < 0.5 ? $l * (1 + $s) : $l + $s - $l * $s;
my $p = 2 * $l - $q;
$r = hue2rgb($p, $q, $h + 1/3);
$g = hue2rgb($p, $q, $h);
$b = hue2rgb($p, $q, $h - 1/3);
}
return [ int($r * 255), int($g * 255), int($b * 255) ];
}
sub rgb_to_html_hex
{
return sprintf "#%.2X%.2X%.2X", @{ $_[0] };
}
my %col1 = ( 'foo' => 1, 'bar' => 1 );
my %col2 = ('foo' => ['cat1','cat1','cat2'],
'bar' => ['cat3','cat2','cat3'] );
my %col3 = ('foo' => [2.3,1.2,1.0],
'bar' => [7.4,4.3,2.2]);
my %cat_colors =
( # Hue Saturation
cat1 => [ 0.00000, 1.00000 ], # Red
cat2 => [ 0.16667, 1.00000 ], # Yellow
cat3 => [ 0.33333, 1.00000 ], # Green
);
sub weight_to_light
{
return 1 - ($_[0] / 10);
}
my %col4;
foreach my $key (keys %col2)
{
foreach my $i ( 0 .. scalar( @{ $col2{$key} } ) - 1 )
{
my $base_color = $cat_colors{ $col2{$key}->[$i] };
my $rgb_color = hsl_to_rgb( @$base_color,
weight_to_light( $col3{$key}->[$i] ) );
my $html_color = rgb_to_html_hex( $rgb_color );
$col4{$key}->[$i] = $html_color;
}
}
use YAML::XS;
say Dump( \%col4 );