4

我有以下数据:

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]);

我想要做的是创建一个看起来像这样但第 4 列的 HTML 表格,其中包含渐变颜色的形状。颜色的强度由分数给出col3。形状可能只是一个简单的项目符号 (• HTML: •)

foo cat1,cat1,cat2 2.3,1.2,1    
bar cat3,cat2,cat3 7.4,4.3,2.2

下图说明了我打算做什么: 在此处输入图像描述

每个颜色类别 (col 3) 的强度范围为 1-10。

最好的方法是什么?

我遇到问题的关键不是创建 HTML 表,我可以做到。但更多的是如何使用渐变颜色创建基于 HTML 的形状。

我坚持使用以下代码:

foreach my $nm (keys %col1) {
   my @cats = @{$col2{$nm}};
   my @vals = @{$col3{$nm}};

   print $nm, " ", join(",",@cats), " " ,join(",",@vals), "\n";
}
4

1 回答 1

4

如果我正确理解了您的问题,那么您并不真正想要具有颜色渐变的形状。您真正想要的是纯色对象,其颜色由两个参数确定:

  • 类别(在您的示例中为 cat1、cat2 和 cat3)
  • 着色程度(第 3 列中的权重)

此外,您示例中的颜色似乎遵循一个模型,其中较小的数字更接近白色,较大的数字更接近黑色,中间的数字是饱和颜色。就色彩空间而言,这暗示了类似于色调、饱和度、亮度色彩空间的内容,如维基百科的这张图片所示:

HSL 色彩空间描述

要将其映射回上面的示例,我怀疑 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 );
于 2013-11-18T06:05:32.963 回答