Python 连续提供最大对比度颜色的算法

Python 连续提供最大对比度颜色的算法,python,colors,color-palette,Python,Colors,Color Palette,我需要生成用于突出显示内容类型的颜色。一份文件中可能有10种颜色 我的用例是,我希望告知科学家如何从输入文档中提取数据。颜色编码的背景着色(带有描述性)工具提示将用于高亮显示导入的块。下面是一个模拟输入文件: 这里是一个模拟版本,它在高亮显示以指示导入了哪些字段时的外观。每个高亮显示的块上的工具提示将提供识别该块的工具的更多详细信息,以及推送到数据库的值(单位): 每次遇到新类型的内容时,我都需要生成新的颜色。该颜色应与现有颜色具有最大对比度。显然,我们走得越远,反差就会越小 在试图想象解决

我需要生成用于突出显示内容类型的颜色。一份文件中可能有10种颜色

我的用例是,我希望告知科学家如何从输入文档中提取数据。颜色编码的背景着色(带有描述性)工具提示将用于高亮显示导入的块。下面是一个模拟输入文件:

这里是一个模拟版本,它在高亮显示以指示导入了哪些字段时的外观。每个高亮显示的块上的工具提示将提供识别该块的工具的更多详细信息,以及推送到数据库的值(单位):

每次遇到新类型的内容时,我都需要生成新的颜色。该颜色应与现有颜色具有最大对比度。显然,我们走得越远,反差就会越小

在试图想象解决这个问题的方法时,我想象了一个色轮。我们从一种颜色开始。要使下一种颜色具有最大对比度,它将与控制盘上的第一种颜色相反

对于每个连续的颜色,算法必须在色轮上寻找最大的“未占用”弧,并在其中点生成颜色

这看起来像任何现有的颜色生成策略吗

如果有,是否有任何成文的算法来实现它


(我的目标环境是Python,但这似乎只是一个实现细节)

啊,我想到了解决这个问题的另一种策略

颜色编码可以推迟到过程结束,而不是动态生成颜色


一旦我们知道需要多少种颜色,我们就可以在HSB/HSV颜色光谱中生成均匀分布在整个色调中的许多排列。我认为,这将提供最大的对比度。

您希望颜色之间的距离相等,并且尽可能远,使用时已插入白色和黑色

一个简单且出人意料的好指标是:

如果你在运行中,你必须用你添加的每种新颜色重新计算颜色的位置,如果你事先知道有多少种颜色,你可以一次计算出它们的位置

下面是python中的一个示例实现:

import numpy as np
from itertools import combinations
from scipy.optimize import minimize, Bounds

BLACK_AND_WHITE = np.array((0.0, 0.0, 0.0, 255.0, 255.0, 255.0))

我们考虑数组中的三个连续数代表一个颜色,给定两个这样的三元组,并且使用上面定义的距离,我们的距离函数是

def distance(c1, c2):
    r = (c1[0] + c2[0]) / 2.0
    coeffs = np.array(((2.0 + r/256), 4, (2.0 + (255 - r)/256.0)))
    diff = c1 - c2
    return np.sqrt(np.sum(coeffs * diff ** 2))
我们希望最大化所有颜色对之间的最小距离,这与最小化负数和最小距离相同。为了获得这些颜色对,我们使用组合(…,2),这正好可以做到这一点,为了使它在三元组上迭代,我们重塑了颜色数组,使每一行都包含一种颜色:

def cost_function(x):
    colors = np.concatenate((BLACK_AND_WHITE, x)).reshape(-1, 3)
    return -min(mean_red_distance(color_pairs[0], color_pairs[1]) for color_pairs in combinations(colors, 2))
现在是最小化成本函数的时候了,颜色允许在0到255之间:

def get_new_colors_after_adding(existing_colors):
    if len(existing_colors):
        guess = np.mod(existing_colors.reshape(-1, 3)[0] + np.array((100, 100, 100)), 256)
    else:
        guess = np.array((0, 255, 255))
    guess = np.concatenate((guess, existing_colors))
    # let all colors range between 0 and 255
    result = minimize(cost_function, guess, bounds=Bounds(0, 255))
    if not result.success:
        raise ValueError('Failed adding new color')
    return result.x
最后,我们在每个步骤中添加10种颜色并打印生成的三元组:

if __name__ == '__main__':
    # start with no colors
    existing_colors = np.empty(0, dtype=np.int32)
    # example of consequently adding colors.
    for i in range(10):
        existing_colors = get_new_colors_after_adding(existing_colors)
        print(np.round(existing_colors.reshape(-1, 3)).astype(np.int))

如果您有其他方法来区分每种类型的内容(例如通过使用字母、名称或数字来标记它们),那么您只需要少数几种不同的颜色来区分它们。一般来说,您不应仅使用颜色来区分不同的项目(例如,请参阅Web内容可访问性指南2.0版)。你能举例说明你希望你的解决方案是什么样子的吗?谢谢@PeterO。已将问题扩展到包括模拟数据。我很担心引入额外的文本,因为用户可能会将其误认为是输入文件中的内容。感谢@feature\u engineer提供了一个详细解释和文档化的解决方案。我担心颜色科学和数学会让我不知所措,但我希望它对其他用户寻求解决这个问题的方法有所帮助。是的,我已经接受了我自己的答案。我发现改变逻辑提供了一个更简单的解决方案。如果答案是由其他人发布的,我也会同样高兴。