Skip to content

Instantly share code, notes, and snippets.

@monkut
Last active March 11, 2021 09:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save monkut/6547cfec029574c9d111edfe1b95b121 to your computer and use it in GitHub Desktop.
Save monkut/6547cfec029574c9d111edfe1b95b121 to your computer and use it in GitHub Desktop.
HLS Color Scaling for legends
from colorsys import rgb_to_hls, hls_to_rgb
class ScaledFloatColorManager:
"""
Intended to provide a scaled legend between to colors in the HSL space
"""
def __init__(self, name, minimum_value, maximum_value, hex_color_min="66b219", hex_color_max="cc0000", display_band_count=6):
self.name = name
self.minimum_value = minimum_value
self.maximum_value = maximum_value
self.hex_min_color = hex_color_min
self.hex_max_color = hex_color_max
self.display_band_count = display_band_count
def get_rgb_tuple(self, color):
"""
:param color: hex string of RGB color, ex: 'FFFFFF'
:returns: tuple of RGB color as integers between 0-255, ex: (255, 255, 255)
Convert hex string value to tuple of ints
'FFFFFF' --> (255, 255, 255)
"""
assert len(self.hex_min_color) == 6
assert len(self.hex_max_color) == 6
color_tuple = []
for idx in range(0, 6, 2):
color_tuple.append(int(color[idx: idx+2], 16))
return tuple(color_tuple)
def value_to_hsl(self, value, as_str=False):
"""
:param value: float value to convert to HSL color
:param as_str: Toggle to force resulting HSL color as a string in the form 'hsl({}, {}%, {}%)'
:type as_str: bool
:returns: HSL color as tuple or string
Convert the given value to the appropriate color
resulting color is represented in HSL (not rgb)
"""
if value < self.minimum_value:
value = self.minimum_value
elif value > self.maximum_value:
value = self.maximum_value
if self.minimum_value < 0:
offset = abs(self.minimum_value)
minimum_value = self.minimum_value + offset
maximum_value = self.maximum_value + offset
value = value + offset
else:
minimum_value = self.minimum_value
maximum_value = self.maximum_value
if all(i == 0 for i in (value, minimum_value, maximum_value)):
scale = 1.0
else:
scale = float(value - minimum_value) / float(maximum_value - minimum_value)
# scale all channels linearly between START_COLOR and END_COLOR
start_rgb = self.get_rgb_tuple(self.hex_min_color)
end_rgb = self.get_rgb_tuple(self.hex_max_color)
# convert rgb to hsl
# --> put rgb values on scale between 0, and 1 for usage with colorsys conversion functions
# results in values 0-1 for all (h,l,s)
start_hls = rgb_to_hls(*[v/255.0 for v in start_rgb])
end_hls = rgb_to_hls(*[v/255.0 for v in end_rgb])
h, l, s = [float(scale * (end-start) + start) for start, end in zip(start_hls, end_hls)]
# adjust to expected scales 0-360, 0-100, 0-100
h *= 360
l *= 100
s *= 100
assert 0 <= h <= 360
assert 0 <= l <= 100
assert 0 <= s <= 100
hsl_color = (int(h), int(s), int(l))
if as_str:
hsl_color = "hsl({}, {}%, {}%)".format(*hsl_color)
return hsl_color
def value_to_rgb(self, value, htmlhex=False, max_rgb_value=255):
"""
:param value: float value to convert to RGB color
:param htmlhex: toggle to return value as html formatted hex, ex: '#FFFFFF'
:returns: RGB color as tuple or string
convert the given float value to rgb color
"""
# flooring value to the limits of the legend
if value < self.minimum_value:
value = self.minimum_value
elif value > self.maximum_value:
value = self.maximum_value
# hsl is used because it is easier to 'rotate' evenly to another color on the spectrum
h, s, l = self.value_to_hsl(value)
# adjust range to be from 0 to 1 change to hls for use with hls_to_rgb()
hls = (h/360.0, l/100.0, s/100.0)
# covert to rgb
if max_rgb_value == 255:
# --> adjust values from 0 to 1, to 0 to 255
rgb = [int(i * 255) for i in hls_to_rgb(*hls)]
else:
rgb= hls_to_rgb(*hls)
if htmlhex:
rgb = "#" + "".join("{:02x}".format(i) for i in rgb)
return rgb
def get_color_str(self, model_instance, model_value_fieldname="value"):
"""
Method for supporting tmstiler Django view
:param model_instance: Model containting a value to 'colorize'
:param model_value_fieldname: fieldname in the model that holds the target 'value"
:return: Color as 'hsl()' string.
"""
value = getattr(model_instance, model_value_fieldname)
return self.value_to_hsl(value, as_str=True)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment