3

I'd like to do the following using Python:

I have a list of several 'hex code color' strings gradated from green to red.

colorGradient = ['#00a500', '#1ea500', '#3ca500', '#5ab400', '#78b400', '#96c300',
                 '#b4d200', '#d2d200', '#f0e100', '#fff000', '#ffd200', '#ffb400',
                 '#ff9600', '#ff7800', '#ff5a00', '#f04b00', '#ff3c00', '#f02d00',
                 '#e11e00', '#d20f00', '#b40000']

Now I have a sequence of integer values. Like this for example..

integer_values = [1, 8, 5, 3, 6, 9]

I'd like to map each value in this sequence to one of the strings in my 'colorGradient' list. The higher the value is, the more red it should be, by contrast: the lower it is, the more green it should be.

Does anyone of you know how to realize this? Is there already a function in the Python standard library which can do that?

martineau
  • 119,623
  • 25
  • 170
  • 301

3 Answers3

1

You need to interpolate:

def gradient_at(x):
    return colorGradient[round(len(colorGradient) - 1) * x)]

def colorize(integer_values):
    max_value = max(integer_values)  # or a known maximal value
    min_value = max(integer_values)  # or a known minimal value

    def color_iter():
        for value in integer_values:
            if min_value != max_value:  # avoid divide by zero
                f = (value - min_value) / (max_value - min_value)
            else:
                f = 0.5

            yield gradient_at(f)

    return zip(integer_values, color_iter())

You may want to rewrite gradient_at to algebraically produce a color such that the transition is continuous.

Eric
  • 95,302
  • 53
  • 242
  • 374
0

If you want to map an arbitrary sequence of integers to a color value, you first need the limits:

minValue, maxValue = min(integer_values), max(integer_values)

You can now calculate a color index by finding the relative position of a value in the range [minValue, maxValue]:

round( ( len( colorGradient ) - 1 ) * float( v - minValue ) / ( maxValue - minValue ) )

When v is the value you want the color for.

Aaron Digulla
  • 321,842
  • 108
  • 597
  • 820
0

Rather than have a fixed sizedcolorGradienttable, I suggest you use a function to map values to a color in the desired range:

# value range
MIN_VAL, MAX_VAL = 0, 10
DELTA_VAL = MAX_VAL - MIN_VAL

# color range
START_COLOR = (0xff,    0, 0)
END_COLOR   = (   0, 0xff, 0)
DELTA_RED   = END_COLOR[0] - START_COLOR[0]
DELTA_GREEN = END_COLOR[1] - START_COLOR[1]
DELTA_BLUE  = END_COLOR[2] - START_COLOR[2]

def color_gradient(val):
    f = float(val-MIN_VAL) / DELTA_VAL
    r = START_COLOR[0] + f*DELTA_RED
    g = START_COLOR[1] + f*DELTA_GREEN
    b = START_COLOR[2] + f*DELTA_BLUE
    return int(r), int(g), int(b)

integer_values = [1, 8, 5, 3, 6, 9]

for val in integer_values:
    print '{} -> #{:02x}{:02x}{:02x}'.format(val, *color_gradient(val))

Output:

1 -> #e51900
8 -> #33cc00
5 -> #7f7f00
3 -> #b24c00
6 -> #669900
9 -> #19e500

There are other ways of interpolating between to RGB colors. See my answers with illustrations to a question titled "Python - Range values to pseudocolor".

Community
  • 1
  • 1
martineau
  • 119,623
  • 25
  • 170
  • 301