0

I have a list of float values that run from negative to positive values. Feel free to use np.random.normal(0, 1, 1000) to randomly generate sample input (random numbers from a normal distribution of mean 0 and standard deviation 1). I'd like to map this array of numbers to the ColorBrewer RdBu red and blue diverging colour bar, such that the smallest number is the darkest blue (assume #053061), and the largest number is the darkest red (assume #b2182b).

I've looked at a similar question about colour gradation, which is close to my question, and in fact is kind of an answer. However, the answer requires generating an array of length, say, 500, that linearly maps between the starting and ending colour, and I would then have to bin my original input data to this colour_array. Surely there's some pre-built functionality somewhere out there that does this already? I may have missed out some kind of documentation somewhere.

AndreyIto
  • 954
  • 1
  • 14
  • 35

1 Answers1

2

In the question you posted, user @zelusp commented on the highest answer and provides a link to a page named Color gradients with Python from a guy named Ben Southgate.

It has a bunch of info on plotting between colors, I think this code from the page covers what you're asking? I think you would use linear_gradient() to make the list for you. The ColorBrewer link looks like the gradient passes through white on the way to the other color, so you could just make two gradients. I cludged on a normalize to the index range of the color gradients from this question.

def hex_to_RGB(hex):
  ''' "#FFFFFF" -> [255,255,255] '''
  # Pass 16 to the integer function for change of base
  return [int(hex[i:i+2], 16) for i in range(1,6,2)]

def RGB_to_hex(RGB):
  ''' [255,255,255] -> "#FFFFFF" '''
  # Components need to be integers for hex to make sense
  RGB = [int(x) for x in RGB]
  return "#"+"".join(["0{0:x}".format(v) if v < 16 else
            "{0:x}".format(v) for v in RGB])

def color_dict(gradient):
  ''' Takes in a list of RGB sub-lists and returns dictionary of
    colors in RGB and hex form for use in a graphing function
    defined later on '''
  return {"hex":[RGB_to_hex(RGB) for RGB in gradient],
      "r":[RGB[0] for RGB in gradient],
      "g":[RGB[1] for RGB in gradient],
      "b":[RGB[2] for RGB in gradient]}

def linear_gradient(start_hex, finish_hex="#FFFFFF", n=10):
  ''' returns a gradient list of (n) colors between
    two hex colors. start_hex and finish_hex
    should be the full six-digit color string,
    inlcuding the number sign ("#FFFFFF") '''
  # Starting and ending colors in RGB form
  s = hex_to_RGB(start_hex)
  f = hex_to_RGB(finish_hex)
  # Initilize a list of the output colors with the starting color
  RGB_list = [s]
  # Calcuate a color at each evenly spaced value of t from 1 to n
  for t in range(1, n):
    # Interpolate RGB vector for color at the current value of t
    curr_vector = [
      int(s[j] + (float(t)/(n-1))*(f[j]-s[j]))
      for j in range(3)
    ]
    # Add it to our list of output colors
    RGB_list.append(curr_vector)

  return color_dict(RGB_list)

gradient1 = linear_gradient("#053061", "#FFFFFF", n=500):
gradient2 = linear_gradient("#FFFFFF", "#b2182b", n=500):

input = np.random.normal(0, 1, 1000)
old_min = min(input)
old_range = max(input) - old_min
new_min = 0
new_range = 999 + 0.9999999999 - new_min
indexable = [int((n - old_min) / old_range * new_range + new_min) for n in input]

for n in indexable:
    if n < 500:
        gradient1[n]
    else:
        gradient2[n]

Maybe something like that

KindaSorta
  • 76
  • 4