我有一系列对象,其ID从1开始递增。我想用不同的、美观的颜色来表示每个对象,这样它们与相邻的对象不会被轻易混淆。虽然颜色不一定是随机的,但我希望输入相同的ID时得到相同的颜色。
我已经检查过所有的方法,试过很多种。最终,使用CIEde2000的蛮力算法,而你最好的选择就是一个静态列表。无论你怎么做,最多只能得到大约30个不同程度的颜色。考虑到色盲和混淆线,你真的会制造出一些障碍物。使用查找表,并修改数据点与颜色以外的其他特征。
#000000
#00FF00
#0000FF
#FF0000
#01FFFE
#FFA6FE
#FFDB66
#006401
#010067
#95003A
#007DB5
#FF00F6
#FFEEE8
#774D00
#90FB92
#0076FF
#D5FF00
#FF937E
#6A826C
#FF029D
#FE8900
#7A4782
#7E2DD2
#85A900
#FF0056
#A42400
#00AE7E
#683D3B
#BDC6FF
#263400
#BDD393
#00B917
#9E008E
#001544
#C28C9F
#FF74A3
#01D0FF
#004754
#E56FFE
#788231
#0E4CA1
#91D0CB
#BE9970
#968AE8
#BB8800
#43002C
#DEFF74
#00FFC6
#FFE502
#620E00
#008F9C
#98FF52
#7544B1
#B500FF
#00FF78
#FF6E41
#005F39
#6B6882
#5FAD4E
#A75740
#A5FFD2
#FFB167
#009BFF
#E85EBE
你可以将id乘以黄金比例(phi)得到一个介于0和1之间的数字n。你生成的所有数字都趋向于均匀分布。
PHI = (1 + sqrt(5))/2
n = id * PHI - floor(id * PHI)
那么问题就在于将该数字转换为颜色,例如:
hue = floor(n * 256)
我写了一篇关于同样主题的文章:
基本上,您可以使用HSV颜色空间,设置固定的饱和度和明度,并修改色相。当您知道所需颜色的数量时,只需通过Hue的范围 [0,1[
分割即可。如果您不知道所需颜色的数量,仍然可以使用黄金比例从此空间选择颜色。
图形设计师知道,如果在信息显示中将使用很多颜色,则这些颜色应该在颜色空间中相对接近。相对于大的跳跃而言,饱和度或色调的小变化通常更好–当涉及许多颜色时,人眼实际上发现当颜色距离不是非常大时更容易吸收信息。
此外,不要忘记您的一些用户可能是色盲。由于有许多不同类型的色盲,很难知道要避免什么颜色组合。也许其他人可以回答这个问题?
class HsbColor
{
public int Hue { get; set; }
public int Saturation { get; set; }
public int Brightness { get; set; }
public Color ToRGB
{
// left as exercise to the reader...
}
}
public class Item
{
public int Id { get; set; }
private static const byte EXPECTED_MAX = 15;
private static int HUE_FACTOR = 255 / EXPECTED_MAX;
public HsbColor Color
{
get {
var color = new HsbColor() { Saturation = 175, Brightness = 175 };
color.Hue = (Id * HUE_FACTOR) % 255;
return color;
}
}
}
我发现与hsl不同,hsluv颜色空间对于随机选择颜色非常有用,因为在我的观点中,那里的颜色更加均匀分布。请参考https://www.hsluv.org/
以下是一个示例:下面的脚本选择了400种不同的颜色,其中0 <= 色调 <= 360,80 <= 饱和度 <= 100(在该范围内均匀选择),亮度基于正态分布选择,平均值为66,标准差为10:
import matplotlib.pyplot as plt
import numpy as np
from hsluv import hsluv_to_rgb
nrows, ncols = 20, 20
h = np.random.uniform(low=0, high=360, size=(nrows, ncols))
l = np.random.normal(loc=66, scale=10, size=(nrows, ncols))
s = np.random.uniform(low=80, high=100, size=(nrows, ncols))
image = np.dstack((h,s,l))
image = np.apply_along_axis(hsluv_to_rgb, 2, image)
plt.figure(figsize=(15,15))
plt.matshow(image, fignum=1)
plt.xticks([])
plt.yticks([])
plt.show()
结果是
这可以与martinus的答案https://dev59.com/yHM_5IYBdhLWcg3w6X1e#5104386或此线程中的其他答案相结合。相比之下,以下示例在hsl颜色空间中具有0 <= hue <= 1,0.4 <= lightness <= 0.6和0.9 <= saturation <= 1:
import matplotlib.pyplot as plt
import numpy as np
from colormap.colors import hls2rgb
nrows, ncols = 20, 20
h = np.random.uniform(low=0, high=1, size=(nrows, ncols))
l = np.random.uniform(low=0.4, high=0.6, size=(nrows, ncols))
s = np.random.uniform(low=0.9, high=1, size=(nrows, ncols))
image2 = np.apply_along_axis(lambda color: hls2rgb(*color), 2, image)
plt.figure(figsize=(15,15))
plt.matshow(image2, fignum=1)
plt.xticks([])
plt.yticks([])
plt.show()
请注意,这里的亮度不同(蓝色和红色方块似乎比黄色或绿色方块更暗)。以下文章解释了原因:https://programmingdesignsystems.com/color/perceptually-uniform-color-spaces/。我有一个简单的解决方案,它独特、稳定但可能不太美观:
color_code = "#" + md5(unique_key_like_email).substring(0, 3)
MD5 方便地生成基于16进制的字符 0-9+a-f,非常适合用于颜色索引。