How to "sort" colors of a particular hue

5.3k Views Asked by At

So if I use randomColor to generate a pretty random variation of "green", I get this for example:

enter image description here

This is a bit chaotic for my liking, I would instead like to get a list of green colors that have some sort of order or sorting to them. That look like they flow into each other. Something more like this:

enter image description here

The question is what principles are being used to sort the colors in that way. I would like to know how I could go about building a grid of colors that would look more pleasant than a random assortment of colors of a specific hue.

The code I used is simply this:

var randomColor = require('randomcolor')

var input = process.argv[2]
var colors = randomColor({
  count: 20,
  hue: input
})

If it makes a difference, I would like to be able to specify the number of rows and columns to divide the colors into as well. Any language or pseudocode would be fine to figure this out, but seeing it in JavaScript, especially if it involves bit manipulation like bitshifts, would be helpful but not necessary.

This doesn't quite seem to do what I want.

2

There are 2 best solutions below

2
Tatarize On BEST ANSWER

The greens on the image run across various hues they then go down in value (get less black) as you move down.

Your pretty color generator randomColor is predicated on an odd theory that colors that move through the golden ratio within the color space will be prettier, basically it just makes sure you tend to get linear steps. But, the code is CC0-Licensed and includes a number of useful things for your purposes. First they define what green is. And they define how to convert from RGB to HSL. I'd just alter that code to make linear steps through the correct hues and then in the row direction step along in value.

However, this is going to just create the same colors each time, so you might just define the list of green colors you like.

If you actually want to sort these colors, you can sort them by literally just sorting them. Use HexToHSB() in the code randomColor, then sort the values based on it's resulting hue value. This generally will have lighter and brighter colors but you can clearly see a less chaotic pattern throughout.

All color spaces tend to be 3 values so putting them in 2d tends to be a bit kludgy, so you might as well pick one or two metrics and use those.

  function HexToHSB(hex) {
    hex = hex.replace(/^#/, '');
    hex = hex.length === 3 ? hex.replace(/(.)/g, '$1$1') : hex;

    var red = parseInt(hex.substr(0, 2), 16) / 255,
      green = parseInt(hex.substr(2, 2), 16) / 255,
      blue = parseInt(hex.substr(4, 2), 16) / 255;

    var cMax = Math.max(red, green, blue),
      cMin = Math.min(red, green, blue),
      delta = cMax - cMin,
      saturation = cMax ? (delta / cMax) : 0;

    switch (cMax) {
      case 0:
        return [0, 0, 0];
      case cMin:
        return [0, 0, cMax];
      case red:
        return [60 * (((green - blue) / delta) % 6) || 0, saturation, cMax];
      case green:
        return [60 * (((blue - red) / delta) + 2) || 0, saturation, cMax];
      case blue:
        return [60 * (((red - green) / delta) + 4) || 0, saturation, cMax];
    }
  }

  var input = 'green'
  var colors = randomColor({
    count: 200,
    hue: input
  })
  colors = colors.sort(function(a, b) {
    var hsva = HexToHSB(a);
    var hsvb = HexToHSB(b);
    return hsva[0] - hsvb[0];
  });
  div = document.createElement("div");
  document.body.appendChild(div);
  colors.forEach(function(element) {
    var d = document.createElement("button");
    d.style.cssText = 'padding:5px; font-size:22px; width:50px; height:50px; background-color:' + element;
    div.appendChild(d);
  });
<script src="https://cdnjs.cloudflare.com/ajax/libs/randomcolor/0.5.4/randomColor.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

0
Caius Jard On

(Not intending this to be a full code inclusive answer)

Your greens in the second image, across the top run from a blue green to a yellow green. In practical terms this means the top left green is “0 red, maybe 255 green and 200 blue”. At the other side, in the top right, it’s maybe “200 red, 255 green, 0 blue”. (I would have made these more accurate by using a colour detector but I’m on a phone)

Descending down the rows they’re tending towards black by reducing the r g b values, so for the middle row they might go from rgb 0,127,100 to rgb 100,127,0

Algorithmically, though this might be easier to do by using hsv colours rather than rgb, as the columns across go from some higher hue to a lower hue and the rows downwards tend from a high value to a low value. This would probably be easier to implement than doing the rgb math as you just need to accept a hue that will vary from maybe h+40 to h-40 (from a full wheel of 360) and a matrix (and you probably will need to ask for rows and columns not just 20, otherwise how will you know to output 5x4 or 4x5)