#!/usr/bin/env python
# coding: utf-8
# # `Spectra` Walkthrough
#
# This notebook provides basic documentation of the [`spectra` Python library](https://github.com/jsvine/spectra), which aims to simplify the process of creating color scales and converting colors from one "color space" to another.
# In[1]:
import spectra
# Note: To visually display the colors we create, let's define and use this `swatches` function:
# In[2]:
from IPython.display import HTML
# In[3]:
swatch_template = """
"""
swatch_outer = """
{0}
"""
# In[4]:
def swatches(colors):
hexes = (c.hexcode.upper() for c in colors)
html = swatch_outer.format("".join(map(swatch_template.format, hexes)))
return HTML(html)
# ## Creating Colors
#
# The easiest way to create a color is to use these shortcuts, one for each "color space" `spectra` supports:
#
# - __`spectra.rgb(r, g, b)`__
# - __`spectra.hsl(h, s, l)`__
# - __`spectra.hsv(h, s, v)`__
# - __`spectra.lab(l, a, b)`__
# - __`spectra.lch(l, c, h)`__
# - __`spectra.cmy(c, m, y)`__
# - __`spectra.cmyk(c, m, y, k)`__
# - __`spectra.xyz(x, y, z)`__
#
# You can also pass a WC3 color name (e.g., `"papayawhip"`) or hexcode (e.g., `"#fefefe"`) to `spectra.html(color)`, which will create the corresponding `rgb` color.
#
# For example:
# In[5]:
swatches([ spectra.html("tomato") ])
# In[6]:
swatches([ spectra.rgb(1, 0.39, 0.28) ])
# ## Getting Color Values
#
# Instances of `spectra.Color` have four main properties:
#
# - __`.values`__: An array representation of the color's values in its own color space, e.g. `(L, a, b)` for an `lab` color.
# - __`.hexcode`__: The hex encoding of this color, e.g. `#ffffff` for `rgb(255, 255, 255)`/`html("white")`.
# - __`.rgb`__: The `(r, g, b)` values for this color in the `rgb` color space; these are allowed to go out of gamut.
# - __`.clamped_rgb`__: The "clamped" `(r, g, b)` values for this color in the `rgb` color space.
#
#
# Note on `.rgb` and `.rgb_clamped`: Spectra follows [colormath](http://python-colormath.readthedocs.org/en/latest/conversions.html?highlight=clamp#rgb-conversions-and-out-of-gamut-coordinates)'s convention:
#
# > RGB spaces tend to have a smaller gamut than some of the CIE color spaces. When converting to RGB, this can cause some of the coordinates to end up being out of the acceptable range (0.0-1.0 or 1-255, depending on whether your RGB color is upscaled). [...] Rather than clamp these for you, we leave them as-is.
# In[7]:
tomato = spectra.lab(62.28, 57.67, 46.29)
# In[8]:
tomato.values
# In[9]:
tomato.rgb
# In[10]:
tomato.clamped_rgb
# In[11]:
tomato.hexcode
# ## Converting Colors
#
# Any `spectra.Color` can be converted to any supported color space, using the __`.to(colorspace)`__ method. E.g.,:
# In[12]:
tomato.to("lch").values
# ## Color Operations
#
# The following `spectra.Color` methods return new colors:
#
# - __`.blend(other_color, ratio=0.5)`__
# - __`.brighten(amount=10)`__
# - __`.darken(amount=10)`__
# - __`.saturate(amount=10)`__
# - __`.desaturate(amount=10)`__
#
# The parameter for __.brighten__/__.darken__ is a positive/negative linear adjustment to the `L`(ightness) value of the color's [Lab](http://en.wikipedia.org/wiki/Lab_color_space) representation. (Spectra converts the color to Lab, makes the change, and then converts back to the original color space.)
#
# Likewise, the parameter for __.saturate__/__.desaturate__ is a positive/negative linear adjustment to the `c`(hroma) value of the color's [Lch representation](http://en.wikipedia.org/wiki/CIELUV#Cylindrical_representation).
# In[13]:
yellow = spectra.html("yellow").to("lab")
# In[14]:
tomato.blend(yellow, 0.25).hexcode
# In[15]:
swatches([
tomato,
tomato.blend(yellow, 0.25),
tomato.blend(yellow, 0.75),
yellow
])
# In[16]:
swatches([
tomato.brighten(30),
tomato,
tomato.darken(30)
])
# In[17]:
swatches([
tomato.saturate(40),
tomato,
tomato.desaturate(40)
])
# ## Color Scales
#
# Color scales translate numbers into colors, based on a set of `colors` and a `domain` (default: 0->1).
# In[18]:
start = spectra.html("#21313E")
end = spectra.html("#EFEE69")
swatches([ start, end ])
# In[19]:
scale = spectra.scale([ start, end ])
# In[20]:
scale(0.5)
# In[21]:
scale(0.5).hexcode
# In[22]:
swatches([
scale(0),
scale(0.5),
scale(1)
])
# To set a custom domain, call `.domain([ start_num, end_num ])`:
# In[23]:
ten_twenty_scale = scale.domain([ 10, 20 ])
# In[24]:
swatches([
ten_twenty_scale(10),
ten_twenty_scale(15),
ten_twenty_scale(20)
])
# The __`.range(count)`__ method produces an evenly-spaced list of colors:
# In[25]:
my_range = ten_twenty_scale.range(10)
# In[26]:
[ x.hexcode for x in my_range ]
# In[27]:
swatches(my_range)
# __`spectra.range(colors, count)`__ provides a shortcut to the same results:
# In[28]:
swatches(spectra.range([ start, end ], 10))
# You can also pass plain hexcode or web-color strings to `range` and `scale`:
# In[29]:
swatches(spectra.range([ "#21313E", "#EFEE69" ], 10))
# The colors produced by scales and ranges depend on the color space you're using. You can change the color space by calling __`.colorspace(space)`__. To wit:
# In[30]:
ranges_html = ""
for space in sorted(spectra.COLOR_SPACES.keys()):
converted_scale = scale.colorspace(space)
ranges_html += "" + space + "
"
ranges_html += swatches(converted_scale.range(10)).data
HTML(ranges_html)
# (Credit to [Gregor Aisch](http://driven-by-data.net/about/chromajs/) for that example.)
# ## Polylinear Scales
#
# You can construct a scale along *any number of colors*. Constructing a scale along three colors can be handy for divergent color schemes. For example, here's a scale that goes from red -> gray -> green instead of directly from red -> green:
# In[31]:
red, gray, green = [ spectra.html(x).to("lab") for x in ("red", "#CCC", "green") ]
polylinear_scale = spectra.scale([ red, gray, green ])
swatches(polylinear_scale.range(9))
# __Note:__ If you want to customize a polylinear scale's `domain`, the *domain must be the same length as the scale itself*. For example:
# In[32]:
polylinear_negpos = polylinear_scale.domain([ -1, 0, 1 ])
# In[33]:
swatches([
polylinear_negpos(-0.75),
polylinear_negpos(0.2),
polylinear_negpos(1)
])
# ## Feedback / Questions
#
# Much appreciated! Please [open an issue](https://github.com/jsvine/spectra/issues) on the [`spectra` GitHub page](https://github.com/jsvine/spectra).
# ---
#
# ---
#
# ---