How to generate different colors of same luminance for line chart in Java?
Asked Answered
G

1

7

I want to generate different colors for my line graphs:

  • I want to generate equally different colors (for human eye)
  • I want them to be the same luminance (not computed brightness)

(this rules out RGB and HSL, YIQ is close but has not perfectly uniform luminance)

Have you used any libraries (in Java) to handle uniform color scheme generation?

I've spent a few days on this issue already, so I'm hoping some of you had the same problem and solved it.

Thanks!

Edit: unfortunately, I cannot use java.awt packages on AppEngine (or anything that uses java.awt.Color).

Glee answered 31/1, 2011 at 9:15 Comment(3)
Have you considered lab color space?Plenum
Yes, it looks promising. But I'd have to spend some more time on that. I'm looking for a solution, so I don't have to spend more days on this topic.Glee
Keep in mind that you are creating usability nightmare for color-blind people, who use mostly luminance to distinguish between red-green shades in charts and such.Homocercal
S
2

Here's a little function I wrote just now from looking at the Wikipedia page http://en.wikipedia.org/wiki/SRGB_color_space

private int makeARGB(double Y, double x, double y) {
  // Out of gamut colour
  int rgb = 0xFF808080;
  double X = Y * x / y;
  double Z = Y * (1 - x - y) / y;
  double rlin = +3.2046 * X + -1.5372 * Y + -0.4986 * Z;
  double r = gamma(rlin);
  int ir = (int) (r * 255.0);
  if (ir >= 0 && ir < 256) {
    double glin = -0.9689 * X + +1.8758 * Y + +0.0415 * Z;
    double g = gamma(glin);
    int ig = (int) (g * 255.0);
    if (ig >= 0 && ig < 256) {
      double blin = +0.0557 * X + -0.2040 * Y + +1.0570 * Z;
      double b = gamma(blin);
      int ib = (int) (b * 255.0);
      if (ib >= 0 && ib < 256) {
        rgb = 0xFF000000 + (ir << 16) + (ig << 8) + (ib << 0);
      }
    }
  }
  return rgb;
}
private double gamma(double l) {
  if (l < 0.0031308) {
    return l * 12.92;
  } else {
    return 1.055 * Math.pow(l, 1.0 / 2.4) - 0.055;
  }
}
private BufferedImage createImage() {
    BufferedImage bm = new BufferedImage(256, 256, BufferedImage.TYPE_INT_ARGB);
    for (int ix = 0; ix < bm.getWidth(); ++ix) {
        double astar = ((double) ix) / ((double) bm.getWidth());
        for (int iy = 1; iy < bm.getHeight(); ++iy) {
            double bstar = ((double) iy) / ((double) bm.getHeight());
            int rgb = makeARGB(0.3, astar, bstar);
            bm.setRGB(ix, iy, rgb);
        }

    }
    return bm;
}

You pass in a luminance Y and colour coordinates x,y. x and y are nominally from 0..1 but a lot of that 'space' is not in the sRGB gamut so doesn't correspond to a displayable colour. Y is also 0..1, try 0.3..0.5 initially.

An example image:gamut with Y=0.3

I don't know anything about google app engine but is an ARGB integer the kind of colour specification you need?

Shaughnessy answered 31/1, 2011 at 12:40 Comment(3)
I rewrote your code to Mirah (java with ruby's syntax) and I allways get 'ff808080' as result, no matter what I pass in. I had to replace "0xFF808080" with Long.parseLong("FF808080", 16) <- can that be what is causeing the problem?Glee
So I managed to make it output some colors (you were right with that 0.3..0.5 space) but they are not very different (they're all yellow-ish). Can you post an example usage to output a collor palete of N colors? Thanks!Glee
Hmm, not easy to generate N colours because the edges of the gamut are a trapezoid (see updated code). I've got 2 more suggestions: either pre-compute an array of RGB colours using standard J2SE (or anything else), I'd use HSL but you that was not suitable, not sure why. OR, calculate a lot of colours in RGB space and put them in a collection, sort by luminance and take a slice of size N from the collection (I can post code for this if you want)Shaughnessy

© 2022 - 2024 — McMap. All rights reserved.