Sometimes one needs to show many data series on one chart. In such cases, usually distinction between those data series is achieved by using different colors for each data set. Most charting libraries leave colors selection to developer. This can be problem when there is need to choose more than six colors which can be easily distinguished by most people. Below you can find Python program which can be helpful.
Program generates palette of colors where each color can be easily distinguished from other colors in its neighborhood. Difference between colors is computed using W3C’s formula for color contrast. Minimum contrast (brightness and color), palette size, neighborhood diameter and maximum number of iterations can be easily set in first few lines of program code.
New colors are created using pseudo-random generators and tested for minimum contrast. If contrast test fails, the color is dropped and new one is created. Besides of minimum required contrast, the size of neighborhood has great impact on probability that test will fail. Too big neighborhood diameter could make it impossible to create complete neighborhood and lock the program. To prevent this, there is limit for number of iterations.
#!/usr/bin/python from random import randint class Color: __c = [0, 0, 0] __cB = None def __init__(self, r=-1, g=-1, b=-1): if r == -1: r = randint(1,255) if g == -1: g = randint(1,255) if b == -1: b = randint(1,255) self.__c = [r, g, b] def __getitem__(self, key): return self.__c[key] def __setitem__(self, key, value): self.__c[key] = value self.__cB = None def getBritness(self): if self.__cB: return self.__cB else: self.__cB = ((self.__c[0] * 299) + (self.__c[1] * 587) + (self.__c[2] * 114)) / 1000 return self.__cB def __sub__(self, other): return ((max(self.__c[0], other[0]) - min(self.__c[0], other[0])) + (max(self[1], other[1]) - min(self[1], other[1])) + (max(self[2], other[2]) - min(self[2], other[2]))) def __str__(self): return "%02x%02x%02x" % (self.__c[0], self.__c[1], self.__c[2]) colors = [] num = 25 comparedNum = 5 c = Color() colors.append(c) stopper = 100000 minBrit = 35 minColDiff = 100 print "searching...", for n in range(num)[1:]: while stopper: newC = Color() passed = 0 for back in range(comparedNum): testedNum = n-(back+1) if testedNum < 0: passed += 1 continue c = colors[testedNum] bDiff = abs(c.getBritness() - newC.getBritness()) cDiff = c - newC if cDiff >= minColDiff and bDiff > minBrit: passed += 1 else: break if passed == comparedNum: colors.append(newC) print "found:", newC, break stopper -= 1 if not stopper > 0: print "searching failed" else: print "finished" html = """ <head> <style> body { margin: 0px; padding: 0px } div { width: %dpx; height: 100px; float: left; } </style> </head> <body> """ % (800/n) python = "colors = (" for c in colors: html += ´<div style="background-color: #%s"></div>\\n´ % c python += ´"%s", ´ % c python = python[:-2] + ")" html += "</body>" out = file("colors.html", "w") print >>out, html print python out.close()