Question

I am working on a simple program to just draw circles around some fixed points using the Python turtle package; however, I wanted to make it somewhat like a heat map where the colors get "cooler" as they get farther from the original point. My idea was to take the base white color, #FFFFFF, and subtract a percentage based from that on the distance away.

I assumed hex color codes worked by getting lower in its hex value as the color gets "cooler", but I have now read that the first two mean its red value, the second its green, and the last its blue. How would I go around implementing a heat map the way I want it to work?

I'm confident the distances are correct, I just think I'm using the color codes in the wrong way. The function I wrote to do the color calculation:

def findColor(dist):
    base = "FFFFFF"
    num = int(base, 16)
    percent = dist/800 #800 is the max distance away
    newNum = (num - (num*percent))
    color = hex(int(newNum))
    return color

The resulting map I get is:

circle heat map

With Ignacio Vazquez-Abrams' help about HSV, I've got it looking like this :) :

Updated color algorithm

Était-ce utile?

La solution

You want to use HSV instead of RGB for the colors; slide across the hue dimension for your distances. colorsys can help.

Autres conseils

The trick is to work on the three bytes individually. I'll give a shot at re-writing your function the way I think it ought to work:

def findColor(dist):
    base = 0xFFFFFF
    percent = dist/800 #800 is the max distance away
    hexpercent = 0xFF - (percent * 0xFF)
    first = (base & 0xFF0000) >> 16
    second = (base & 0xFF00) >> 8
    third = base & 0xFF
    color = hex(((first - hexpercent) << 16) | ((second - hexpercent) << 8) | (third - hexpercent))
    return color

I isolate each byte, subtract the percentage from each byte, and then re-assemble the bytes into an integer. There might be a more clever way to do this, but it ought to give you a steady gradient of grays. (Work on just 0xFF0000 or 0xFF00 or 0xFF if you want a steady gradient of red, green, or blue.)

Note that this doesn't take any physiological properties of color into account -- there might be more pleasing ways to approach this. (Actual color specialists were quite upset with the web-safe colors that were selected by computer scientists to be pleasing because of the numbers involved...)

Here's code that will interpolate any multi-color gradient. It's set up to do white > red > green > blue > black, but it's easy to change it to any other gradient.

The range for the 'd' parameter is 0 to 1, so if you have larger distances you may wish to scale them down for use in this function.

The code takes colors in RGB, but converts them into HSV for nicer interpolation.

import colorsys
import math

GRADIENT_SPEC = [
    (1.0, 1.0, 1.0),  # white
    (1.0, 0.0, 0.0),  # red
    (0.0, 1.0, 0.0),  # green
    (0.0, 0.0, 1.0),  # blue
    (0.0, 0.0, 0.0)]  # black

def gradient(d, spec=GRADIENT_SPEC):
    N = len(spec)
    idx = int(d * (N - 1))
    t = math.fmod(d * (N - 1), 1.0)
    col1 = colorsys.rgb_to_hsv(*spec[min(N - 1, idx)])
    col2 = colorsys.rgb_to_hsv(*spec[min(N - 1, idx + 1)])
    hsv = tuple(a * (1 - t) + b * t for a, b in zip(col1, col2))
    r, g, b = colorsys.hsv_to_rgb(*hsv)
    return '#%02X%02X%02X' % (r * 255, g * 255, b * 255)

for x in xrange(12):
    print x, gradient(x / 10.0)
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top