Update palettes to use HSL coloring
Introduce a new function called `hsl_colors` and a helper `quantize` function that creates palettes using HSL values on the fly. Default palettes are now split into "<colorname>-dark" and "<colorname>-light" for more variation. In my experiments, red-centric colors seem to be more distinguishable than others. You have red, green, blue - you can tell they're distinct. Interleaved between these you have yellow, cyan, and magenta, also distinct. But between yellow and green, or green and cyan, these colors feel less distinct than orange, purple or pink. I have opted to elide non-red "in-betweens" such as those. So we have a dark and light variant of the following colors as palettes: red, orange, yellow, green, cyan, blue, purple, magenta, pink, gray, and also a rainbow palette that is every color at its full saturation. Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
@@ -41,15 +41,108 @@ class StaticPalette(Palette):
|
||||
return self.colors[color]
|
||||
|
||||
|
||||
HSVRange = range | float | int | list[float | int]
|
||||
|
||||
|
||||
def quantize(r: range, steps: int = 16) -> list[float]:
|
||||
"""
|
||||
Given a range and a number of steps, create a list of numbers starting and ending in the range
|
||||
(inclusive) with that number of steps.
|
||||
|
||||
:param r: the range to quantize.
|
||||
:param steps: the number of steps to use.
|
||||
:returns: a list of the quantized range.
|
||||
"""
|
||||
dist = abs(r.stop - r.start)
|
||||
return [r.start + (i * dist / (steps - 1)) for i in range(steps)]
|
||||
|
||||
|
||||
def hsl_colors(hue: HSVRange, sat: HSVRange, light: HSVRange) -> list[str]:
|
||||
"""
|
||||
Utility method to create 16 colors using HSL.
|
||||
|
||||
:param hue: the hue, or range of hues, to use for this palette.
|
||||
:param sat: the saturation, or range of saturations, to use for this palette.
|
||||
:param light: the light value, or range of light values, to use for this palette.
|
||||
"""
|
||||
|
||||
if isinstance(hue, (float, int)):
|
||||
hue = [hue] * 16
|
||||
elif isinstance(hue, range):
|
||||
hue = quantize(hue)
|
||||
assert len(hue) == 16, "hue values must be a list of 16 elements"
|
||||
|
||||
if isinstance(sat, (float, int)):
|
||||
sat = [sat] * 16
|
||||
elif isinstance(sat, range):
|
||||
sat = quantize(sat)
|
||||
assert len(sat) == 16, "saturation values must be a list of 16 elements"
|
||||
|
||||
if isinstance(light, (float, int)):
|
||||
light = [light] * 16
|
||||
elif isinstance(light, range):
|
||||
light = quantize(light)
|
||||
assert len(light) == 16, "light values must be a list of 16 elements"
|
||||
|
||||
return [f"hsl({h:.02f},{s:.02f}%,{l:.02f}%)" for h, s, l in zip(hue, sat, light)]
|
||||
|
||||
|
||||
DEFAULT_PALETTES = {
|
||||
"red": StaticPalette([f"#{0x110000 * i:06x}" for i in range(0x10)]),
|
||||
"green": StaticPalette([f"#{0x001100 * i:06x}" for i in range(0x10)]),
|
||||
"blue": StaticPalette([f"#{0x000011 * i:06x}" for i in range(0x10)]),
|
||||
"black": StaticPalette([f"#{0x111111 * i:06x}" for i in range(0x10)]),
|
||||
"cyan": StaticPalette([f"#{0x001111 * i:06x}" for i in range(0x10)]),
|
||||
"yellow": StaticPalette([f"#{0x111100 * i:06x}" for i in range(0x10)]),
|
||||
"magenta": StaticPalette([f"#{0x110011 * i:06x}" for i in range(0x10)]),
|
||||
"white": StaticPalette([f"#{0x111111 * (0xF - i):06x}" for i in range(0x10)]),
|
||||
# Interesting thing with human perception.
|
||||
# Between red and yellow, we can perceive "orange". We have a name for it and see it as a
|
||||
# distinct color. However, between yellow and green, we see a sickly green; between green and
|
||||
# cyan, a seafoam green; between cyan and blue, a lighter blue.
|
||||
#
|
||||
# Beside these, I think that between blue and magenta gives a color you could safely call
|
||||
# "purple", and between magenta and red, you get a color you could safely call "pink". It seems
|
||||
# that reds are more distinct to the human eye.
|
||||
#
|
||||
# For this reason, I have decided to pick these palettes as the "defaults", with a "dark" and
|
||||
# "light" variant of each (lightness 0-50%, and 50-100% respectively), with an additional
|
||||
# fully-saturated "rainbow" palette with all of the colors:
|
||||
#
|
||||
# red, orange, yellow, green, cyan, blue, purple, magenta, pink, gray, rainbow
|
||||
|
||||
"red-light": StaticPalette(hsl_colors(0, 100, range(50, 100))),
|
||||
"red-dark": StaticPalette(hsl_colors(0, 100, range(0, 50))),
|
||||
|
||||
"orange-light": StaticPalette(hsl_colors(30, 100, range(50, 100))),
|
||||
"orange-dark": StaticPalette(hsl_colors(30, 100, range(0, 50))),
|
||||
|
||||
"yellow-light": StaticPalette(hsl_colors(60, 100, range(50, 100))),
|
||||
"yellow-dark": StaticPalette(hsl_colors(60, 100, range(0, 50))),
|
||||
|
||||
#"lime-light": StaticPalette(hsl_colors(90, 100, range(50, 100))),
|
||||
#"lime-dark": StaticPalette(hsl_colors(90, 100, range(0, 50))),
|
||||
|
||||
"green-light": StaticPalette(hsl_colors(120, 100, range(50, 100))),
|
||||
"green-dark": StaticPalette(hsl_colors(120, 100, range(0, 50))),
|
||||
|
||||
#"seafoam-light": StaticPalette(hsl_colors(150, 100, range(50, 100))),
|
||||
#"seafoam-dark": StaticPalette(hsl_colors(150, 100, range(0, 50))),
|
||||
|
||||
"cyan-light": StaticPalette(hsl_colors(180, 100, range(50, 100))),
|
||||
"cyan-dark": StaticPalette(hsl_colors(180, 100, range(0, 50))),
|
||||
|
||||
#"teal-light": StaticPalette(hsl_colors(210, 100, range(50, 100))),
|
||||
#"teal-dark": StaticPalette(hsl_colors(210, 100, range(0, 50))),
|
||||
|
||||
"blue-light": StaticPalette(hsl_colors(240, 100, range(50, 100))),
|
||||
"blue-dark": StaticPalette(hsl_colors(240, 100, range(0, 50))),
|
||||
|
||||
"purple-light": StaticPalette(hsl_colors(270, 100, range(50, 100))),
|
||||
"purple-dark": StaticPalette(hsl_colors(270, 100, range(0, 50))),
|
||||
|
||||
"magenta-light": StaticPalette(hsl_colors(300, 100, range(50, 100))),
|
||||
"magenta-dark": StaticPalette(hsl_colors(300, 100, range(0, 50))),
|
||||
|
||||
"pink-light": StaticPalette(hsl_colors(330, 100, range(50, 100))),
|
||||
"pink-dark": StaticPalette(hsl_colors(330, 100, range(0, 50))),
|
||||
|
||||
"gray-dark": StaticPalette(hsl_colors(0, 0, range(0, 50))),
|
||||
"gray-light": StaticPalette(hsl_colors(0, 0, range(50, 100))),
|
||||
|
||||
"rainbow": StaticPalette(hsl_colors(range(0, 360), 100, 50)),
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user