#!/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 = """
{0}
""" 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). # --- # # --- # # ---