如何生成对比明显的颜色?

6

我的应用程序包含一条折线图,可以同时显示20个或更多的数据集,但通常只会显示少于5个。我希望每个数据集都有一个独特的颜色。

目前我的做法是:

setHsl(i * 255.0 / session->getNumDataSets(), 255, 128);

它可以工作,但缺点是连续的两个数据集颜色非常相似。我希望每个生成的颜色都与前面所有生成的颜色形成最大对比度。

有没有更好的方法来生成颜色呢?

这是我的第二次尝试:

double pos = 0;
if (wheel.size() == 0)
{
    wheel.append(0.0);
    wheel.append(1.0);
}
else
{
    double gap = 0;
    double hi = 0;
    double lo = 0;

    for (int i = 0; i < wheel.size() - 1; i++)
    {
        double g = wheel[i + 1] - wheel[i];
        if (g > gap)
        {
            gap = g;
            lo = wheel[i];
            hi = wheel[i + 1];
        }
    }

    pos = (hi - lo) / 2.0 + lo;

    wheel.append(pos);
    qSort(wheel);
}

QColor c;
c.setHsl(pos * 255.0, 255, 128);
return c.toRgb();

我的想法是,第一种颜色在色轮上的位置为0。然后对于每个接下来的颜色,我围绕着色轮寻找颜色之间最大的间隙,并在该间隙中插入一个新颜色。这似乎效果更好,但仍然不完美,因为一旦间隙变小,连续的颜色又变得相似起来。


通常最大对比度使用纯色(亮度=120,饱和度=240),确保你已经选择了色调。 - Wrikken
他不想再像以前那样选择色调了,因为相邻的颜色非常相似。 - Reinderien
我刚刚在 Reddit 或者 Hacker News 上看到了一篇很好地解决了这个问题的博客文章,但现在我找不到它了。 - Roland Rabien
4个回答

5
我知道你想要计算生成图表颜色的方法,但你可能需要考虑设计一个自定义调色板并从预存的表格中查找颜色。
这样做的好处是可以为色盲用户创建一系列更易于区分的颜色。您可以使用VisCheck等工具查看您的图表在色盲用户眼中的显示效果。
如果您有超过20个数据集,仅通过颜色进行区分可能会非常困难,但可以将颜色与其他区分因素(例如虚线)结合使用。

3
您可以这样做:
int n = session->getNumDataSets();
setHsl( (((i%3) * n/3)+(i/3)) * 255.0 / n, 255, 128);

我需要再核对一下我的计算,但基本上它会在光谱中的三分之一之间旋转。


不太起作用,以交替顺序给出相同的3种颜色,但我认为我理解了你的意图。 - Roland Rabien
现在试一下 - 其中一个模块应该是除法。 - Reinderien
看起来非常不错,谢谢。比我的第二次尝试简单多了。 - Roland Rabien

2

我在Java中使用以下函数为不同数据集创建等间距颜色,用于生成图表。它简短而精简:

/**
 * This function splits the red-green-blue colour wheel into n equally spaced divisions
 * and returns the colour from a particular division.
 * 
 * @param index The index of the colour to return, the range is 0 - (count-1)
 * @param count The number of divisions to split the HSV colour wheel into
 * @return A java.awt.Color object containing the colour.
 * @author HughesR
 */
public static Color getSpacedOutColour(int index, int count) {
    final float saturation = 0.95f; // Saturation
    final float brightness = 0.8f;  // Brightness
    float hue = (float)index / (float)count;
    return Color.getHSBColor(hue, saturation, brightness);
}

这也是我使用的方法。非常方便。相关问答在此 - aioobe

2
不要使用HSL。它的缺陷是为什么在HSL(或同样糟糕的HSV)空间中“数值上看起来不同”的颜色最终在你的眼中看起来相似。相反,使用YUV(也称为YCbCr)。如果您不熟悉YUV的基本思想是进行线性变换,使第一个轴成为“感知”强度,类似于:
Y = 0.3*R + 0.6*G + 0.1*B

通常使用更细调的系数,但这些是简单的系数,可以让您大致了解权重。

然后选择第二个和第三个轴作为平面中与Y轴正交的两个向量,通常是大致“红色”和“蓝色”方向。

请注意,由于颜色在RGB坐标中被限制为一个立方体,因此一旦您选择了Y值,这会对保持在框内的可能U和V值设置界限。在Y=max时,U和V必须为零。因此,请选择一些亮度中等的Y值,在UV平面的极坐标中均匀地选择N个向量。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接