# How to pick a color differing significantly from the colors already in a given color list?

Suppose that we want to color a number of objects. We start by selecting some color (randomly). Then we want the color of the next object to be significantly different from the colors already used (including the background color, say white). After a number of attempts I was unable to find any smart way to do this. Suppose that the RGBColor model is used. Then my best result was

cl = {RGBColor[1., 1., 1.]};

myFun1[colList_List, {x_?NumericQ, y_?NumericQ, z_?NumericQ}] :=
Last[ColorDistance[colList, RGBColor[x, y, z], DistanceFunction->"CIE94"]]

oneStep1[cl_List] :=
(Append[cl, RGBColor[x, y, z] /.
Last[NMaximize[
{myFun1[cl, {x, y, z}], 1 >= x >= 0, 1 >= y >= 0, 1 >= z >= 0},
{x, y, z}]]])

Nest[oneStep1, cl, 5]


Clearly, the result is not good enough (I need at leas 10 significantly different colors).

• Any reason why you couldn't use a pre-defined color space? Table[ColorData["BrightBands"][i], {i, 0, 1, .1}] There are a number of both continuous and discrete sets. Sep 29 '15 at 13:09
• @user18792 Isn't this the same question: mathematica.stackexchange.com/questions/38722/…? Sep 29 '15 at 16:45
• Or possibly this: mathematica.stackexchange.com/questions/23647/…? Sep 29 '15 at 16:47
• Is it really necessary to search for suitable colors one after another? I think results should be more pleasant when they're optimized all together. Sep 29 '15 at 17:05
• Predefined colors is not good for the following reasons:
– Acus
Sep 30 '15 at 6:47

Here's one approach, attempting to find a sufficiently good local maximum for minimum color difference of ten colors differing from black and white, and each other:

Module[
{sRGB, toLCH, oldcolors, ncolors, newcolorvars, newcolors, allcolors},
sRGB = Import["sRGB_v4_ICC_preference.icc"];
toLCH = ColorConvert[#, sRGB -> "LCH"] &;
oldcolors = {Black, White};
ncolors = 10;
newcolorvars = Array[c, {ncolors, 3}];
allcolors = Join[oldcolors, newcolorvars];
newcolors = RGBColor @@@
(newcolorvars /. Last@Quiet@NMaximize[
Min[
ColorDistance[toLCH@#1, toLCH@#2,
DistanceFunction -> "CIE2000"] & @@@
Subsets[allcolors, {2}]],
Flatten@newcolorvars \[Element]
Cuboid[Table[0, {3 ncolors}]],
Method -> "SimulatedAnnealing",
MaxIterations -> 1000000000]);
Join[oldcolors, newcolors]]


Pairwise comparison visualization of selected colors:

Table[Graphics@{Circle[],
Table[{#[[i]],
Disk[{0, 0},
1, \[Pi]/2 - (2 \[Pi]/Length@#) {i - 1, i}]}, {i,
Length@#}] &@#, {i, Disk[{0, 0}, 2/3]}}, {i, #}] &@%


There are multiple problems in this implementation:

• ColorDistance seems to require unexplained pre-conversion to LCH colorspace to work acceptably. In general, there's something deeply disturbing in colorspace handling Mathematica does - or doesn't seem to do, sometimes. Linear and non-linear colorspaces are not intuitively separate, or compatible, for instance.
• NMaximize has trouble trying to find good maxima because ColorDistance is only numeric and the domain has lots of local maxima.
• ColorDistance functions in general are not even meant to perform large color separation measures, but rather ones very close to a reference color. (Related commentary: Is ColorDistance symmetric?)
• Min is not necessary a sensible aesthetic metric. Something like Mean@# / Variance@# & might make more sense, but is takes forever in practice.
• ColorDistance seems to require unexplained pre-conversion to LCH colorspace to work acceptably Could you make an example about this point? ColorDistance should work with any supported color directive. Linear and non-linear colorspaces are not intuitively separate, or compatible, for instance RGB-based spaces are non-linear, CIEXYZ is linear while LAB and LUV are not (L is a non-linear transformation of Y). Not sure about what you mean by compatible here. Mar 17 '16 at 12:56
• @Batracos This is really an unscientific hunch. I'm feeling that colors converted from "traditional" RGBColor to other spaces, or other spaces to RGBColor getting displayed on the notebook sometimes fail to observe linearity (or non-linearity) correctly. I haven't really pinpointed an exact way to demonstrate this, though. Mar 17 '16 at 13:04