vaab / colour

Python color representations manipulation library (RGB, HSL, web, ...)
BSD 2-Clause "Simplified" License
319 stars 41 forks source link

feature request: pseudo-continuous color ranges for numeric data #33

Open ekiefl opened 7 years ago

ekiefl commented 7 years ago

Is there a one-liner that I can use to get the color of a numeric value? For example, I want to make a color range from blue to red using 256 levels, where blue somehow maps to 0.0 and red maps to 1.0. From the markdown file I've come up with the following workflow.

from colour import Color
import numpy as np

# make the base colors
red = Color("red")
blue = Color("blue")

# define the color range
levels = 256
r_to_b = list(red.range_to(blue, levels))

def map(x, color_range, m=0.0, M=1.0):
    """ This map converts a numeric value to Color object in a list of Color objects """
    n = len(color_range)
    numeric_range = np.linspace(m,M,n)
    nearest_idx = np.abs(x - numeric_range).argmin()
    return color_range[nearest_idx]

# retrieve the color of float x
x = 0.2425
color_x = map(x, r_to_b)

Is this functionality already present in colour, or do you see a better implementation?

vaab commented 7 years ago

Your workflow is basically correct. To resume: You can use the Color(source).range_to(target, N) to manage color scales and generate a N level definition way between source color and target color. This gives you arbitrary precision at the cost of memory. Please remember that the scaling between the colors will use HSL for now, so it has some use to have a better resolution than 256, even if your final output will be RGB.

Without numpy considerations (and thus with probable rounding and typing issues):

import colour import Color

def mk_map(source, target, levels=1024):
    range = list(Color(source).range_to(Color(target), levels))
    def map(x, m=0.0, M=1.0):
        return range[min(int(levels * (x - m) / (M - m)), levels - 1)]
    return map

## Usage
map = mk_map("red", "blue", 2048)

map(0.0)  ## returns Color("blue")
map(1.0)  ## return Color("red")

It might be a good idea to provide this functionality (mapping continuous value to color scales) indeed. I'll look into this when I'll have more time.