Sorting colors (colours)
October 2, 2007 11:46 AM   Subscribe

How does one sort hexadecimal colors properly?

I figured I could sort them from 0-9a-f but look at the following colors:
#000000 <>blue?  wtf!
#838383 <>
posted by furtive to Computers & Internet (17 answers total) 6 users marked this as a favorite
Grrr... the preview gave completely different output that what we see here.

What I meant to show was:

#555555 <-- dark grey
#686868 <-- a bit lighter grey
#6aa8bf <-- blue? WTF
#838383 <-- lighter grey
#a0a0a0 <-- even lighter grey

I suppose this has something to do with the three dimensionality of colors, but any advice on a more proper sorting algorithm would be appreciated.
posted by furtive at 11:48 AM on October 2, 2007

I don't think that came through OK
posted by RustyBrooks at 11:49 AM on October 2, 2007

pre-sorted gif
posted by desjardins at 11:51 AM on October 2, 2007

The way you have them, you're sorting by redness, then green-ness, then blueness.

Probably you're going to have to convert the colors to something like HSV, and sort by that, H first (hue) then S (saturation) then V (value/brightness)

That should get you closer to what you want.
posted by RustyBrooks at 11:51 AM on October 2, 2007

is the question how do i sort hexadecimal representations of colors such that like colors are next to one another? for example sort them from lightest to darkest?
posted by phil at 11:53 AM on October 2, 2007

In fact, look at desjardin's table, in the "HSL" column... I'd probably rank the ordering differently but you can see that the ordering here is by L then S then H
posted by RustyBrooks at 11:55 AM on October 2, 2007

Desjardins, the table you link to is the sort of order I'd like to output to, but I require the logic behind it. For example, if you sroll to the end you'll notice that the last three colors are:


... how do they know that #9E0508 goes between the two #E3 colors? What's the secret?

On preview, Rusty appears to have what I'm looking for.
posted by furtive at 11:56 AM on October 2, 2007

Colors just don't have a canonical linear ordering, so the first thing you have to decide is how you want them sorted. If you can't even describe how you'd do it by hand, you're SOL for coming up with an algorithm.

So, according to your needs, what's the right order for #555555, #686868, #6aa8bf, #838383, and #a0a0a0 to be in, and why?
posted by Wolfdog at 11:58 AM on October 2, 2007

here is an example of the algorithm for to converting RGB to HSV.
posted by phil at 11:59 AM on October 2, 2007

These are RGB values, and you're sorting first on the magnitude of red, then on the magnitude of green, then on the magnitude of blue. So yeah, the color you're wondering about there looks really blue because it's got just about twice as much blue in it as the one before it, and half again as much blue as the one after. No wonder it sticks out.

If you had more colors in this list, you'd notice it breaks up into ranges: The amount of redness increases smoothly from beginning to end, but within each level of redness you've got your own steady increase from no greenness to full greenness. Then when you step up one level of redness there's a jump, because greenness starts from the bottom again. Ditto within the greenness levels for the blueness sublevels. Your path through the three-dimensional color space is discontinuous, and that shows up in the palette as sharp contrasts.

If you've got a bunch of colors, you could make that all at least a little smoother by taking a continuous path through the color space, winding back and forth: Sort ascending on red, then within odd-numbered redness levels sort ascending on green, but within even-numbered ones, sort the greens descending. This is easy to visualize if you look at the red-green space as a two-dimensional page: You're drawing a long snake back and forth. But then you've got to do the same windy thing to the blue levels within each green level, and that's not so easy to visualize. In the odd-numbered greenness levels, sort blues the same direction as the greens, but in the even-numbered ones, sort them opposite.

That being said, if you do that with a small number of colors in the palette, there are still going to be plenty of discontinuities. To make the colors transition with the best smoothness, you have to solve a traveling-salesman problem: Find the distance between each two colors (square root of the sum of the squares of the red, green, and blue differences respectively), lay them out in a big old table, and find the shortest path that visits each one. The bad news is that this belongs to the hardest known category of computable problems. The good news is that it's easier when there aren't very many items, which is precisely when you need it.

On preview, sorting in a different color space, like HSV, is likely to be more satisfactory. You can do the same refinements as here (alternating directions, traveling salesman least-distance) but the output is more likely to be acceptable without them. Agreed that you need to get clear on what you're looking for.
posted by eritain at 12:16 PM on October 2, 2007

Thanks for the great answers so far.
posted by furtive at 12:25 PM on October 2, 2007

My new line of attack is to convert the hex to HSL and order by that.
posted by furtive at 12:33 PM on October 2, 2007

The major problem is that you're trying to map three dimensional values onto one dimension. This is what results in the wave pattern (either sawtooth or smooth if you do extra work)--which frankly is not very satisfactory (as anyone who spent way too much time in kindergarten trying to organize a big box of crayons can tell you). Here is the proper way to sort colors, given only two dimensions. You can get a somewhat better (although more difficult to look at) approximation of three if you remove, say, value from the sphere and make it a slider along the bottom, a la GIMP.
posted by anaelith at 2:01 PM on October 2, 2007

As you've already mentioned, colour is 3 dimensional - representing it in 2 dimensions is difficult and there is no 'proper' way to do it.

To output as a table I'd do something like this:

start table
  for r = 0 to 255 step 16
    start row
    for g = 0 to 255 step 16
      for b = 0 to 255 step 16
        draw cell - background color rgb
      end for b
    end for g
    end row
  end for r
end table
posted by missmagenta at 2:11 PM on October 2, 2007

Here is the proper way to sort colors, given only two dimensions.

Even the 'sphere'/colour wheel is imperfect - no grey. They have black on the outside and white at the center but there is no way to go from white to black, because you can't move in the 3rd axis.
posted by missmagenta at 2:24 PM on October 2, 2007

sortpal is some perl code I wrote ages ago to sort gimp pallets (basically just text files of hex colors). The page itself has some examples which might give you some ideas on what different ways of sorting look like.

One thing I never got around to coding that might be interesting is to sort by distance from the origin in a color cube. Assume R/G/B (or whatever color space) happens to map to a cube (they dont, but...) and then sort by which ever point is closest to 0,0,0 in 3d space.
posted by alikins at 3:47 PM on October 2, 2007

Using the HSV color space is a good idea, but if you really want to have colors next to each other in the list be similar, you could try using a space filling curve like the Hilbert curve. This would reduce discontinuities when you jumped from one hue to the next. Also, you could try other color spaces, like XYZ or Lab. Of course, this may be unnecessary for your particular application.
posted by demiurge at 5:51 PM on October 2, 2007

« Older No Mosque for me, thank you, I'm full   |   Help my wife not fear the doctor's office Newer »
This thread is closed to new comments.