Palettes

A palette is a collection of colors that you want to use to make special lighting effects. By pre-choosing your colors you can play around with effects and keep within your “theme.”

For example, if you want to have a fire/flame looking project, pick a palette with red, orange, yellow and maybe white. If you want an ice/frost looking project, pick a palette with dark blue, cyan, and white. Nature lovers will want green tints.

Traditionally in computer graphics, color palettes have a start and an end, and a finite number of entries, usually a power of two, often dictated by graphics hardware. 16- and 256-entry color palettes are commonly seen, and that’s what the FastLED Arduino library supports.

FancyLED is just software…it’s not bound by physical hardware constraints…and its concept of color palettes is a little different. The number of palette entries can be anything…could be five, could be 50. The sequence “loops around” — there doesn’t need to be a start or finish, and you can reference colors between the palette entries, it’s not just discrete steps.

Like hue explained on the prior page, colors are drawn from a palette with a floating-point index, where 0.0 and 1.0 represent the beginning of the list and…well, not the end, but back to the beginning of the list. It can be any number but will “wrap around” in this range. This is a boon for LED animation, which tends to be cyclical.

Here’s how a color palette with four entries might be referenced:

Code-wise, color palettes in FancyLED are simply Python lists where each entry is a CRGB, CHSV or packed integer color:

my_palette = [fancy.CRGB(0, 0, 0),       # Black
              fancy.CHSV(1.0),           # Red
              fancy.CRGB(1.0, 1.0, 0.0), # Yellow
              0xFFFFFF]                  # White

You can mix-and-match color types if you like…they don’t need to all be CRGB or CHSV. A palette can also be a tuple (bounded by (parenthesis) rather than [brackets]) if you know your palette is set in stone (or want to enforce that). Lists give more flexibility for replacing or adding new elements.

Use the palette_lookup() function to retrieve a color from a palette list, passing the palette name and floating-point position as arguments:

color = fancy.palette_lookup(my_palette, 0.3)

Like the mix() function explained on the previous page…if the requested color is between two CHSV colors, the return value of palette_lookup() will also be a CHSV type. In all other cases it returns a CRGB type (even if the palette is using packed integers).

The circular nature of FancyLED palettes does not preclude access to the original discrete colors, or treating the last entry as the palette end. One option is to use fractions in a call to palette_lookup(), where the denominator is the number of palette entries and the numerator is the index (0 to length-1) … e.g. 0, 1/4, 2/4 and 3/4 with a 4-element palette like the one above. But in most cases it’s easier to bypass the library and pull from the palette list directly:

color = my_palette[3]

Gradient Palettes

Taking a cue from FastLED and from Photoshop’s gradient tool, there’s a second type of color palette that’s sometimes more concise, but requires some extra steps to set up…

Here’s a view of Photoshop’s gradient designer tool. Notice there are four “stops” (the markers just below the gradient)…but, unlike our color palettes described above, these are not evenly spaced. Each stop can be positioned anywhere along the gradient, though they do need to be in increasing positions along its length.

This one has stops at 0%, 30%, 83% and 100%.

A similar gradient in FancyLED would be expressed as a list of tuples, each containing two elements: the location of the stop (from 0.0 at the beginning to 1.0 at the end) and a color (any supported format — CRGB, CHSV or RGB packed integer).

The copper gradient above could be expressed as:

grad = [(0.0, 0x97461A),
        (0.3, 0xFBD8C5),
        (0.83, 0x6C2E16),
        (1.0, 0xEFDBCD)]

However…you can’t just pull a color from a gradient list using palette_lookup(). The uneven spacing would make it inordinately slow.

Instead, we first convert the gradient to a regular (equal interval) palette using the expand_gradient() function, with two arguments: the gradient list source, and the number of entries we want in the resulting palette:

palette = fancy.expand_gradient(grad, 50)

How many entries in the output palette is a balance been RAM (always in short supply) and how faithfully we want to reproduce the gradient palette. The copper gradient above might look good enough with just a dozen palette entries (then interpolating in-between with palette_lookup()), while really intricate gradient setups might need 100 or more.

Once converted, colors can be read (from the converted palette, not the original) using palette_lookup():

color = fancy.palette_lookup(palette, 0.42)
Last updated on Jan 27, 2018 Published on Feb 01, 2018