2

I have an ArrayList<Double>, the values of which are converted into slices of an Arc2D.Pie graph based on size (i.e., an array of {1d,1d,2d,4d} would create a graph with four slices, two of which occupy an eighth of the graph each, one of which occupies a fourth, and one of which occupies a half; together, the slices would be arranged to form a full circle). Each of these slices is colored differently both to allow for easy mapping of slices to other indicators (names, etc.) and to avoid blandness.

My algorithm for selecting colors was initially quite simple:

public Color getColor(int index, int total) {
    return Color.getHSBColor((float) index / (float) total, 1f, 1f);
}

However, while this works well with most colors (red and blue, to name a few), some, such as cyan (especially prominent as the second element in a set of two; e.g., an array of {1d, 3d}) are not easily viewable by the human eye, as they are too light.

I have since changed the algorithm to

return Color.getHSBColor((float) index / (float) total, 1f, 0.8f);

in an attempt to darken the colors; however, cyan is still hard to see, and lowering the brightness further makes the colors rather hard to distinguish.

Does anyone have a nice, preferably simple algorithm that will create a spectrum of colors that are all easily viewable? A good test would be to generate yellowish and cyanish colors and see if they are easily viewable on a white background.

Thanks!

WC

EDIT: I have now improved my algorithm to make more varied colors, by varying saturation and lightness. The colors look choppier, though; any more ideas?

New algorithm:

float hue = (float) seriesIndex / (float) totalSeries;
int steps = 4;
float saturation = ((seriesIndex) % steps / (2f * steps)) + (0.5f);
float brightness = ((seriesIndex + ((steps + 1) / 2f)) % (steps + 1f) / (2f * (steps + 1f))) + 0.5f;
Color c = Color.getHSBColor(hue, saturation, brightness);
wchargin
  • 15,589
  • 12
  • 71
  • 110

2 Answers2

1

I like greyscale

 Color.rgb( 255 * (float)index/(float)total, 255 * (float)index/(float)total, 255 *      (float)index/(float)total);

Otherwise, the field of color segmentation is pretty big. Some people are okay breaking it up into bands.

Otherwise, if you just need 4 colors, I would pick ones that work good and pick from a table: Such as Red, Blue, Green and Black.

nmjohn
  • 1,432
  • 7
  • 16
  • Yes, this is very good for small amounts, but once you get past 15 items it starts to look a bit messy. What do you mean by the "field of color segmentation?" – wchargin Jan 09 '12 at 07:06
  • I think you're going to run into a problem in general with finding any large number of colors that all look distinct and not messy. Color segmentation is used in a lot of fields to algorithmically shade different types of data. This usually doesn't go beyond 4 or 5 colors (e.g. medical imaging) or the colors are meant to blend together (to display different bone densities). Could you also post up some sample images? I'm curious what they look like with the different algorithms and item counts. – nmjohn Jan 09 '12 at 07:10
  • Keep in mind that I am colorblind. Anyway! 5 colors you can distiguish easily: [link](http://img846.imageshack.us/img846/1955/5colors.png); 10 is a bit harder, but doable: [link](http://img35.imageshack.us/img35/3991/tencolorsn.png); 30, you don't stand a chance: [link](http://img820.imageshack.us/img820/8392/30colors.png). – wchargin Jan 09 '12 at 08:13
  • Also: I'm writing a graph engine, so I want the end developer (likely, me later) to be able to specify however many pie slices he wants without worrying about color at all. – wchargin Jan 09 '12 at 08:15
  • Ah, colorblindness will make them quite a bit harder to distinguish. I agree, the 30 is impossible for a lot of the red and blue shades. How many items are you trying to do total? This may be a more color theory question for selecting the colors, but there may not be a good way to do it algorithmically. – nmjohn Jan 09 '12 at 08:17
  • I'd like it to be unlimited (although the end developer will have to be reasonable). I've also taken a look at [this](http://stackoverflow.com/a/43235/732016); if I could take the randomness out that would be great. I'll try that with creating a custom `Random` object. – wchargin Jan 09 '12 at 08:45
1

The best algorithm I've found so far uses a previous SO algorithm that's I've modified. I keep MIX at a constant light gray (Color.LIGHT_GRAY), and use a seeded Random object so that the color is always the same for each iteration, but different between.

Random random = new Random(seriesIndex);
int red = random.nextInt(256);
int green = random.nextInt(256);
int blue = random.nextInt(256);

// mix the color
if (MIX != null) {
    red = (red + MIX.getRed()) / 2;
    green = (green + MIX.getGreen()) / 2;
    blue = (blue + MIX.getBlue()) / 2;
}

Color c = new Color(red, green, blue);

It turns out with nice-looking colors that are fairly discernable.

Example image

Thanks to nmjohn for helping me solve this, giving me ideas, and pointing me in the right direction!

WC

NOTE: I'll leave this open for two days. If anyone comes up with a nicer algorithm, I'll accept his. Otherwise, I'll accept this.

Community
  • 1
  • 1
wchargin
  • 15,589
  • 12
  • 71
  • 110