_images/toyplot.png

Colors

Color choices are critical in visualization because good color choices can reveal or emphasize patterns in your data while poor choices will obscure them. This section of the user guide will introduce Toyplot’s basic functionality for creating and manipulating colors. See Color Mapping for details on how to represent your data using color.

Color Values

Colors in Toyplot are represented as red-green-blue-alpha (RGBA) tuples, where each component can range from zero (off) to one (full strength). Alpha is used to represent the opacity of a color, from zero (completely transparent) to one (completely opaque). There are a variety of functions in Toyplot for creating color tuples using CSS strings, RGBA data, and even other color spaces:

import toyplot.color
toyplot.color.rgb(1, 0, 0)
# Note: transparent red is *not* the same as opaque pink!
toyplot.color.rgba(1, 0, 0, 0.5)
toyplot.color.css("mediumseagreen")
toyplot.color.css("#248")
# CIE Lab color space:
toyplot.color.lab(75, 0, -100)
# Toyplot uses this as a default instead of pure black:
toyplot.color.black
'#292724'

Color Palettes

In practice you should rarely need to manipulate individual color values as much of the color management in Toyplot centers around palette objects, which store ordered collections of colors. For example, consider Toyplot’s default palette:

toyplot.color.Palette()

You will likely recognize the colors in the default palette, since they are used to specify per-series colors when adding multiple data series to a figure. Although you can create your own custom palettes by passing a sequence of color values to the toyplot.color.Palette constructor, we strongly recommend that you use the high-quality palettes from Color Brewer which are included with Toyplot and ideal for visualization. As we will see shortly, the Toyplot default palette is itself an example of a Color Brewer palette.

Each of the Color Brewer palettes is assigned to one of three categories, “sequential”, “diverging”, or “qualitative”, which we will discuss in-turn:

Color Brewer Sequential Palettes

Sequential color palettes are designed to visualize magnitudes for some quantity of interest. Colors at one end of the palette are mapped to low values and colors at the opposite end map to high values. Toyplot includes the complete set of Color Brewer sequential palettes, ordered so that colormaps based on these palettes always map low values to low luminance and high values to high luminance:

import IPython.display
for name, palette in toyplot.color.brewer.palettes("sequential"):
    IPython.display.display_html(IPython.display.HTML("<b>%s</b>" % name))
    IPython.display.display(palette)
BlueGreen
BlueGreenYellow
BluePurple
Blues
BrownOrangeYellow
GreenBlue
GreenBluePurple
GreenYellow
Greens
Greys
Oranges
PurpleBlue
PurpleRed
Purples
RedOrange
RedOrangeYellow
RedPurple
Reds

Color Brewer Diverging Palettes

Diverging palettes are especially useful when visualizing signed magnitudes, or magnitudes relative to some well-defined reference point, such as a mean, median, or domain-specific critical value. Once again, Toyplot includes the complete set of Color Brewer diverging palettes, ordered consistent so that low/negative values map to cooler colors and high/positive values map to warmer colors:

for name, palette in toyplot.color.brewer.palettes("diverging"):
    IPython.display.display_html(IPython.display.HTML("<b>%s</b>" % name))
    IPython.display.display(palette)
BlueGreenBrown
BlueRed
BlueYellowRed
GrayRed
GreenYellowRed
PinkGreen
PurpleGreen
PurpleOrange
Spectral

Color Brewer Qualitative (Categorical) Palettes

Qualitative or categorical palettes are designed for visualizing unordered information. Adjacent colors typically have high contrast in hue or luminance, to emphasize boundaries between values. Toyplot includes the full set of qualitative palettes from Color Brewer, without modification:

for name, palette in toyplot.color.brewer.palettes("qualitative"):
    IPython.display.display_html(IPython.display.HTML("<b>%s</b>" % name))
    IPython.display.display(palette)
Accent
Dark2
Paired
Pastel1
Pastel2
Set1
Set2
Set3

Usage

Color brewer palettes are created by name. For example, the following is the equivalent of Toyplot’s default palette:

toyplot.color.brewer.palette("Set2")

And here is a palette that is commonly used for diverging data:

toyplot.color.brewer.palette("BlueRed")

You can lookup the set of all available palette names:

toyplot.color.brewer.names()
['Accent',
 'BlueGreen',
 'BlueGreenBrown',
 'BlueGreenYellow',
 'BluePurple',
 'BlueRed',
 'BlueYellowRed',
 'Blues',
 'BrownOrangeYellow',
 'Dark2',
 'GrayRed',
 'GreenBlue',
 'GreenBluePurple',
 'GreenYellow',
 'GreenYellowRed',
 'Greens',
 'Greys',
 'Oranges',
 'Paired',
 'Pastel1',
 'Pastel2',
 'PinkGreen',
 'PurpleBlue',
 'PurpleGreen',
 'PurpleOrange',
 'PurpleRed',
 'Purples',
 'RedOrange',
 'RedOrangeYellow',
 'RedPurple',
 'Reds',
 'Set1',
 'Set2',
 'Set3',
 'Spectral']

Or you can lookup names for a specific category:

toyplot.color.brewer.names("diverging")
['BlueGreenBrown',
 'BlueRed',
 'BlueYellowRed',
 'GrayRed',
 'GreenYellowRed',
 'PinkGreen',
 'PurpleGreen',
 'PurpleOrange',
 'Spectral']

Alternatively, given a palette name, you can lookup its category:

toyplot.color.brewer.category("BlueRed")
'diverging'

When creating a palette, you can reverse the order of its color values (though this should almost never be necessary, thanks to the careful ordering of the palettes):

toyplot.color.brewer.palette("BlueRed", reverse=True)

Each of the Color Brewer palettes comes in multiple variants with different numbers of colors. By default, when you create a Color Brewer palette, the one with the maximum number of colors is returned. However, you can query for all of the available variants, and request one with fewer colors if necessary:

toyplot.color.brewer.counts("BlueRed")
[3, 4, 5, 6, 7, 8, 9, 10, 11]
toyplot.color.brewer.palette("BlueRed", count=5)

Palette Manipulation

Sometimes you’ll find yourself needing categorical palettes with more categories than the existing Color Brewer palettes provide. For these cases, you’ll have to create larger palettes on your own, but Toyplot can still help. First, the toyplot.color.spread() function can create a family of colors based on a single color value:

toyplot.color.spread("mediumseagreen", lightness=0.9)
toyplot.color.spread(toyplot.color.rgb(1, 0.8, .05), lightness=0.2, count=6)

Of course, this isn’t a complete solution, because you can only create so many colors of a single hue before they become indistinguishable. However, Toyplot makes it easy to concatenate palettes:

toyplot.color.spread("steelblue", count=6) + toyplot.color.spread("crimson", count=5)

Using this approach, you can, within reason, build-up arbitrarily large palettes. Often, the two-level hierarchy created by the combination of palette hues and lightness is useful for visually grouping families of related categories.

Color Maps

While palettes group together related collections of color values, Toyplot uses color maps to perform the real work of mapping data values to colors. Some color maps are based on the colors contained in a palette, while others calculate color values based on the subtleties of the human visual cortex; regardless, all color maps perform the basic function of mapping a collection of scalar values to a collection of colors.

Categorical Color Maps

The simplest type of color map in Toyplot is a toyplot.color.CategoricalMap, which uses scalar values as an index to lookup color values from a palette. As you might have guessed, if you create a default categorical map, it uses Toyplot’s default palette:

toyplot.color.CategoricalMap()

However, you can create a categorical map explicitly using any palette:

toyplot.color.CategoricalMap(toyplot.color.brewer.palette("Set1"))

As a convenience, toyplot.color.BrewerFactory.map() can be used to create a map from any categorical Color Brewer palette:

toyplot.color.brewer.map("Set1")

Although a palette contains a finite number of colors, a categorical map “wraps” out-of-range scalar values so that any scalar value can be mapped to a color, albeit causing the colors to repeat:

colormap = toyplot.color.brewer.map("Set1", count=3)
colormap
colormap.colors([-1, 0, 1, 2, 3, 4, 5])

Categorical maps are primarily designed to be used with integers; however, floating point values are automatically truncated to integers during mapping:

colormap.colors([0, 0.25, 0.75, 1, 1.25])

Linear Color Maps

The most used type of color map in Toyplot is a toyplot.color.LinearMap, which uses linear interpolation to map a continuous range of data values to a continuous range of colors, specified using a palette. Unsurprisingly, Toyplot provides a default linear colormap, which is based on a diverging palette:

toyplot.color.LinearMap()

And as before, you can create linear maps either explicitly using palettes, or using the toyplot.color.BrewerFactory.map() convenience function:

toyplot.color.LinearMap(toyplot.color.brewer.palette("BlueRed"))
toyplot.color.brewer.map("BlueRed")

Here are complete lists of the linear maps that can be created from the sequential and diverging Color Brewer palettes:

for name, colormap in toyplot.color.brewer.maps("sequential"):
    IPython.display.display(IPython.display.HTML("<b>%s</b>" % name))
    IPython.display.display(colormap)
BlueGreen
BlueGreenYellow
BluePurple
Blues
BrownOrangeYellow
GreenBlue
GreenBluePurple
GreenYellow
Greens
Greys
Oranges
PurpleBlue
PurpleRed
Purples
RedOrange
RedOrangeYellow
RedPurple
Reds
for name, colormap in toyplot.color.brewer.maps("diverging"):
    IPython.display.display(IPython.display.HTML("<b>%s</b>" % name))
    IPython.display.display(colormap)
BlueGreenBrown
BlueRed
BlueYellowRed
GrayRed
GreenYellowRed
PinkGreen
PurpleGreen
PurpleOrange
Spectral

Miscellaneous Linear Maps

In addition to linear maps based on the Color Brewer palettes, Toyplot provides a handful of additional high-quality color maps that can be created by name using toyplot.color.LinearFactory.map(), for example:

toyplot.color.linear.map("Blackbody")

Here is the full list of additional linear maps:

toyplot.color.linear.names()
['Blackbody', 'ExtendedBlackbody', 'Kindlmann', 'ExtendedKindlmann']
for name, colormap in toyplot.color.linear.maps():
    IPython.display.display(IPython.display.HTML("<b>%s</b>" % name))
    IPython.display.display(colormap)
Blackbody
ExtendedBlackbody
Kindlmann
ExtendedKindlmann

Moreland Diverging Maps

As an alternative to linear maps, Toyplot also provides a set of nonlinear diverging color maps based on “Diverging Color Maps for Scientific Visualization” by Ken Moreland at http://www.sandia.gov/~kmorel/documents/ColorMaps. The Moreland maps are carefully crafted to provide a perceptually uniform mapping that takes both color and luminance into account to eliminate Mach banding effects. Unsurprisingly, they are created by name using toyplot.color.DivergingFactory.map():

toyplot.color.diverging.map("PurpleOrange")

And here are examples of the available maps:

toyplot.color.diverging.names()
['BlueBrown', 'BlueRed', 'GreenRed', 'PurpleGreen', 'PurpleOrange']
for name, colormap in toyplot.color.diverging.maps():
    IPython.display.display(IPython.display.HTML("<b>%s</b>" % name))
    IPython.display.display(colormap)
BlueBrown
BlueRed
GreenRed
PurpleGreen
PurpleOrange

Color Maps and Perception

What do we mean when we speak of “high quality” color palettes and maps? While the choice of color palettes and interpolations may seem to be one of personal taste, not all color pairings are equal! The human visual system is much more sensitive to changes in luminance than changes in hue, so we typically want to use color maps that create linear changes in luminance where there are linear changes in the underlying data. To illustrate this point, the following figures will plot the relationship between data and luminance for all of the colormaps we’ve seen.

First, we will look at colormaps based on the Color Brewer sequential palettes:

import docs
docs.plot_luma(toyplot.color.brewer.maps("sequential"))
0.00.51.0050100BlueGreen0.00.51.0050100BlueGreenYellow0.00.51.0050100BluePurple0.00.51.0050100Blues0.00.51.0050100BrownOrangeYellow0.00.51.0050100GreenBlue0.00.51.0050100GreenBluePurple0.00.51.0050100GreenYellow0.00.51.0050100Greens0.00.51.0050100Greys0.00.51.0050100Oranges0.00.51.0050100PurpleBlue0.00.51.0050100PurpleRed0.00.51.0050100Purples0.00.51.0050100RedOrange0.00.51.0050100RedOrangeYellow0.00.51.0050100RedPurple<