by Jeffrey Rosenbluth on December 4, 2013

Tagged as: , , .

Introducing the Palette Package, Part II

In part 1 of this post we talked mostly about borrowing a set of colors that was made by someone else. In this part we talk about tools we can use to make our own color schemes.

Most software provides some type of color picker for selecting a single color. To choose a color we are often given the choice between several different color panels, including a color wheel, color sliders, and others. The sliders metaphor works well for choosing a single color, but it doesn't provide us with an intuitive way to choose a color scheme.

The color wheel is more promising. A color wheel is designed to have pure hues on the perimeter, that means saturation and brightness are set to 100%. If you look at this type of color wheel, that is one based on HSB or HSL, you will notice that the red, green and blue sections are 120 degrees apart. If you look at Adobe Kuler on the other hand you will see that red and green lie on opposite poles of the wheel. That's a better way to visualize the color wheel since red and green are complimentary colors (They produce black or white when combined in the correct proportions). Complimentary colors

The point is that when picking colors for a scheme, traditional color harmony defines which colors are chosen by choosing a base color and other colors on the wheel at specific angles apart. The wheel that is used though is one with complimentary colors opposite each other like in Kuler. This is the so called traditional or artist's color wheel. We call it the RYB (red, yellow, blue) wheel since it is based on those three being the primary colors and colors in between as mixtures of those.

The RYB color wheel and the color schemes we will design below are easy to view using the wheel function. wheel takes a list of colors and makes a color wheel out of them by placing the first color in the list at the top of the wheel.

> wheel cs = wheel' # rotate r
>   where
>     wheel' = mconcat $ zipWith fc cs (iterateN n (rotate a) w)
>     n = length cs
>     a = 1 / (fromIntegral n) @@ turn
>     w = wedge 1 xDir a # lwG 0
>     r = (1/4 @@ turn)  ^-^  (1/(2*(fromIntegral n)) @@ turn)

Here is the RYB color wheel. Notice that colors we perceive as opposites, e.g. red and green are 180 degrees apart on the wheel. In harmony the RYB color wheel is created by shrinking and stretching sections of the HSB color wheel so that complimentary colors are always on opposite sides of the wheel.

> ryb = [rybColor n | n <- [0..23]]
> example = wheel ryb

Although we have described the base color as a pure hue, we are actually free to choose any color we like at the base color. In order to create the harmonies we desire, we want a function that takes a given color and returns the color a certain number of degrees away on the RYB wheel. For that harmony provides the function rotateColor. Here is the original d3 color set and the same set rotated by 60 degrees (counter clockwise).

> d3 = [d3Colors1 n | n <- [0..9]]
> example = hcat' (with & sep .~ 0.5) [bar d3, bar $ map (rotateColor 60) d3]

Let's pick a base color to demonstrate the classic color harmonies and how to use the Harmony functions. How about a nice mustardy yellow "#FFC200".

Since we have been talking about complimentary colors, the first scheme we describe is unsurprisingly called Complimentary. It's based on two complimentary colors and in the Harmony module three other colors are chosen by shading and tinting those two colors.

> example = hcat' (with & sep .~ 0.5) [ bar (take 2 (complement base))
>                                     , wheel $ complement base]

A Monochromatic color harmony consists of the base color plus various tints, shades and tones.

> example = wheel $ monochrome base

The following scheme does not have a name as far as I know. We take the base color and mix a little bit of it into black, grey, and white. In Harmony the function is called bwg.

> example = wheel $ bwg base

Sometimes it is useful to view a color scheme like a wheel but with the base color as a disc in the center. We define the function pie for this purpose.

> pie (c:cs) = ring <> center
>   where
>     center = circle 0.5 # fc c # lwG 0
>     ring = mconcat $ zipWith fc cs (iterateN n (rotate a) w)
>     n = length cs
>     a = 1 / (fromIntegral n) @@ turn
>     w = annularWedge 0.5 1 xDir a # lwG 0

The Analogic color scheme is the base color plus the two colors 30 degrees apart on each side. As usual we add in some tints, shades, and tones to fill out a 5 color scheme. Accent Analogic is similar but we add in the color complimentary to the base color.

> example = hcat' (with & sep .~ 0.5) [ pie $ analogic base
>                                     , pie $ accentAnalogic base]

The lase two schemes provided by Harmony are Triad, with colors 120 degrees apart and Tetrad with colors on the corners of a rectangle inscribed in the color wheel.

> example = hcat' (with & sep .~ 0.5) [ pie $ triad base
>                                     , pie $ tetrad base]