如果我正确理解了您的问题,那么您并不真正想要具有颜色渐变的形状。您真正想要的是纯色对象,其颜色由两个参数确定:
- 类别(在您的示例中为 cat1、cat2 和 cat3)
- 着色程度(第 3 列中的权重)
此外,您示例中的颜色似乎遵循一个模型,其中较小的数字更接近白色,较大的数字更接近黑色,中间的数字是饱和颜色。就色彩空间而言,这暗示了类似于色调、饱和度、亮度色彩空间的内容,如维基百科的这张图片所示:
要将其映射回上面的示例,我怀疑 0.0 附近的权重将位于双锥体的顶部附近,10.0 附近的权重将在双锥体的底部附近,并且您的类别表示的颜色具有固定的色调和饱和度(理论上在双锥赤道附近)由这些权重调整。
以下 perl 代码将 HSL 颜色转换为 RGB。它改编自这个 StackOverflow 答案,而后者又改编自我上面链接的 Wikipedia 页面。这只是必要解决方案的一部分:
##
## 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) ];
}
这个函数接受一个 HSL 颜色,比如(0, 1.0, 0.5)
纯红色,并返回一个 RGB 三元组[ 255, 0, 0 ]
。这给了你一个难题。
根据我从您的问题陈述中可以看出的内容,您有一组基色,您可能可以用色调和饱和度来表达,按类别排序。像这样的东西:
my %cat_colors =
( # Hue Saturation
cat1 => [ 0.00000, 1.00000 ], # Red
cat2 => [ 0.16667, 1.00000 ], # Yellow
cat3 => [ 0.33333, 1.00000 ], # Green
);
OP 更新:这太棒了。要在更多类别中添加颜色,可以在此网站中查看“色调”值:http: //www.color-hex.com/。请注意,例如,该网站声明红色的 HSL 是:0.00 1.00 0.50
。
注意:你肯定想玩这些颜色。如果您有 Photoshop 或其他可以让您根据不同颜色空间查看颜色的工具,那么这可能会帮助您为每个类别选择“基本”颜色,使其完全符合您的要求。对于hsl_to_rgb
上面的代码,您需要将色调和饱和度值缩放到 [0, 1] 范围内。
现在我们如何将其应用于您上面给出的权重参数?正如我上面所说,它似乎直接映射到 HSL 中的亮度参数,权重 0.0 映射到白色,权重 10.0 映射到黑色。(至少,首先,考虑到你的草图,这似乎是一个很好的起点。)然而,在 HSL 中,1.0 是白色的,0.0 是黑色的。因此,要将重量映射到亮度,您需要这样的表达式:
$lightness = 1 - ($weight / 10);
您可以将其包装在一个函数中:
sub weight_to_light
{
return 1 - ($_[0] / 10);
}
等式中的最后一部分是将返回的 RGB 映射hsl_to_rgb
到 HTML 可以使用的东西。这其实很简单。以下简短函数将 R、G、B 值数组从hsl_to_rgb
转换为 HTML 就绪的十六进制字符串:
sub rgb_to_html_hex
{
return sprintf "#%.2X%.2X%.2X", @{ $_[0] };
}
所以,把它们放在一起:如果你想生成一个名为%col4
给定详细信息的哈希%col2
,%col3
其中包含你需要在 HTML 中根据上面的着色模型为对象着色的字符串,你需要上面的两个函数,%cat_colors
映射,和一些这样的代码:
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;
}
}
生成%col4
后,您可以使用生成的 HTML 字符串为各个实体着色。我的现代 HTML 有点生疏,但我知道诸如此类的构造<FONT COLOR="#xxxxxx">
曾经一次有效,并且可能仍然有效。我留给你从计算的值构造语法上有效且足够现代的 HTML。
现在,您必须承认,我对您要解决的问题以及需要如何解决它做出了一些大胆的假设。不过,我认为,我在一般情况下。如果您有任何疑问,请随时发表评论。
而且...为了您的剪切和粘贴方便,这是一个快速测试程序,我将上述所有位以及您的示例数据集复制到一个独立的、可测试的 perl 程序中。享受!最后两行使用 YAML::XS 转储计算值,%col4
以便我可以查看它们是否合理。
#!/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 );