I wrote the two methods below to automatically select N distinct colors. It works by defining a piecewise linear function on the RGB cube. The benefit of this is you can also get a progressive scale if that's what you want, but when N gets large the colors can start to look similar. I can also imagine evenly subdividing the RGB cube into a lattice and then drawing points. Does anyone know any other methods? I'm ruling out defining a list and then just cycling through it. I should also say I don't generally care if they clash or don't look nice, they just have to be visually distinct.

public static List<Color> pick(int num) {
    List<Color> colors = new ArrayList<Color>();
    if (num < 2)
        return colors;
    float dx = 1.0f / (float) (num - 1);
    for (int i = 0; i < num; i++) {
        colors.add(get(i * dx));
    }
    return colors;
}

public static Color get(float x) {
    float r = 0.0f;
    float g = 0.0f;
    float b = 1.0f;
    if (x >= 0.0f && x < 0.2f) {
        x = x / 0.2f;
        r = 0.0f;
        g = x;
        b = 1.0f;
    } else if (x >= 0.2f && x < 0.4f) {
        x = (x - 0.2f) / 0.2f;
        r = 0.0f;
        g = 1.0f;
        b = 1.0f - x;
    } else if (x >= 0.4f && x < 0.6f) {
        x = (x - 0.4f) / 0.2f;
        r = x;
        g = 1.0f;
        b = 0.0f;
    } else if (x >= 0.6f && x < 0.8f) {
        x = (x - 0.6f) / 0.2f;
        r = 1.0f;
        g = 1.0f - x;
        b = 0.0f;
    } else if (x >= 0.8f && x <= 1.0f) {
        x = (x - 0.8f) / 0.2f;
        r = 1.0f;
        g = 0.0f;
        b = x;
    }
    return new Color(r, g, b);
}

当前回答

对于Python用户来说,seaborn非常简洁:

>>> import seaborn as sns
>>> sns.color_palette(n_colors=4)

它返回RGB元组列表:

[(0.12156862745098039, 0.4666666666666667, 0.7058823529411765),
(1.0, 0.4980392156862745, 0.054901960784313725),
(0.17254901960784313, 0.6274509803921569, 0.17254901960784313),
(0.8392156862745098, 0.15294117647058825, 0.1568627450980392)]

其他回答

如果N足够大,你会得到一些相似的颜色。世界上只有这么多。

为什么不把它们均匀地分布在光谱中,像这样:

IEnumerable<Color> CreateUniqueColors(int nColors)
{
    int subdivision = (int)Math.Floor(Math.Pow(nColors, 1/3d));
    for(int r = 0; r < 255; r += subdivision)
        for(int g = 0; g < 255; g += subdivision)
            for(int b = 0; b < 255; b += subdivision)
                yield return Color.FromArgb(r, g, b);
}

如果您想混合序列,以便相似的颜色不在彼此旁边,您可能会打乱结果列表。

是我想得不够周全吗?

就像Uri Cohen的答案,但它是一个生成器。首先要把颜色分开。确定的。

样品,左边颜色先:

#!/usr/bin/env python3
from typing import Iterable, Tuple
import colorsys
import itertools
from fractions import Fraction
from pprint import pprint

def zenos_dichotomy() -> Iterable[Fraction]:
    """
    http://en.wikipedia.org/wiki/1/2_%2B_1/4_%2B_1/8_%2B_1/16_%2B_%C2%B7_%C2%B7_%C2%B7
    """
    for k in itertools.count():
        yield Fraction(1,2**k)

def fracs() -> Iterable[Fraction]:
    """
    [Fraction(0, 1), Fraction(1, 2), Fraction(1, 4), Fraction(3, 4), Fraction(1, 8), Fraction(3, 8), Fraction(5, 8), Fraction(7, 8), Fraction(1, 16), Fraction(3, 16), ...]
    [0.0, 0.5, 0.25, 0.75, 0.125, 0.375, 0.625, 0.875, 0.0625, 0.1875, ...]
    """
    yield Fraction(0)
    for k in zenos_dichotomy():
        i = k.denominator # [1,2,4,8,16,...]
        for j in range(1,i,2):
            yield Fraction(j,i)

# can be used for the v in hsv to map linear values 0..1 to something that looks equidistant
# bias = lambda x: (math.sqrt(x/3)/Fraction(2,3)+Fraction(1,3))/Fraction(6,5)

HSVTuple = Tuple[Fraction, Fraction, Fraction]
RGBTuple = Tuple[float, float, float]

def hue_to_tones(h: Fraction) -> Iterable[HSVTuple]:
    for s in [Fraction(6,10)]: # optionally use range
        for v in [Fraction(8,10),Fraction(5,10)]: # could use range too
            yield (h, s, v) # use bias for v here if you use range

def hsv_to_rgb(x: HSVTuple) -> RGBTuple:
    return colorsys.hsv_to_rgb(*map(float, x))

flatten = itertools.chain.from_iterable

def hsvs() -> Iterable[HSVTuple]:
    return flatten(map(hue_to_tones, fracs()))

def rgbs() -> Iterable[RGBTuple]:
    return map(hsv_to_rgb, hsvs())

def rgb_to_css(x: RGBTuple) -> str:
    uint8tuple = map(lambda y: int(y*255), x)
    return "rgb({},{},{})".format(*uint8tuple)

def css_colors() -> Iterable[str]:
    return map(rgb_to_css, rgbs())

if __name__ == "__main__":
    # sample 100 colors in css format
    sample_colors = list(itertools.islice(css_colors(), 100))
    pprint(sample_colors)

上面有很多非常好的答案,但如果有人正在寻找一个快速的python解决方案,那么提到python包distinctify可能会很有用。它是pypi提供的一个轻量级包,使用起来非常简单:

from distinctipy import distinctipy

colors = distinctipy.get_colors(12)

print(colors)

# display the colours
distinctipy.color_swatch(colors)

它返回一个rgb元组列表

[(0, 1, 0), (1, 0, 1), (0, 0.5, 1), (1, 0.5, 0), (0.5, 0.75, 0.5), (0.4552518132842178, 0.12660764790179446, 0.5467915225460569), (1, 0, 0), (0.12076092516775849, 0.9942188027771208, 0.9239958090462229), (0.254747094970068, 0.4768020779917903, 0.02444859177890535), (0.7854526395841417, 0.48630704929211144, 0.9902480906347156), (0, 0, 1), (1, 1, 0)]

此外,它还有一些额外的功能,比如生成不同于现有颜色列表的颜色。

我们只需要一个RGB三联体对的范围,这些三联体之间的距离最大。

我们可以定义一个简单的线性渐变,然后调整渐变的大小以获得所需的颜色数量。

在python中:

from skimage.transform import resize
import numpy as np
def distinguishable_colors(n, shuffle = True, 
                           sinusoidal = False,
                           oscillate_tone = False): 
    ramp = ([1, 0, 0],[1,1,0],[0,1,0],[0,0,1], [1,0,1]) if n>3 else ([1,0,0], [0,1,0],[0,0,1])
    
    coltrio = np.vstack(ramp)
    
    colmap = np.round(resize(coltrio, [n,3], preserve_range=True, 
                             order = 1 if n>3 else 3
                             , mode = 'wrap'),3)
    
    if sinusoidal: colmap = np.sin(colmap*np.pi/2)
    
    colmap = [colmap[x,] for x  in range(colmap.shape[0])]
    
    if oscillate_tone:
        oscillate = [0,1]*round(len(colmap)/2+.5)
        oscillate = [np.array([osc,osc,osc]) for osc in oscillate]
        colmap = [.8*colmap[x] + .2*oscillate[x] for x in range(len(colmap))]
    
    #Whether to shuffle the output colors
    if shuffle:
        random.seed(1)
        random.shuffle(colmap)
        
    return colmap

您可以使用HSL颜色模型来创建颜色。

如果你想要的只是不同的色调(可能),以及亮度或饱和度的轻微变化,你可以像这样分配色调:

// assumes hue [0, 360), saturation [0, 100), lightness [0, 100)

for(i = 0; i < 360; i += 360 / num_colors) {
    HSLColor c;
    c.hue = i;
    c.saturation = 90 + randf() * 10;
    c.lightness = 50 + randf() * 10;

    addColor(c);
}