.. _palette_tutorial: .. currentmodule:: seaborn

Choosing color palettes

Color is even more important than other aspects of figure style, because color can reveal patterns in the data if used effectively or hide those patterns if used poorly. There are a number of great resources to learn about good techniques for using color in visualizations, I am partial to this `series of blog posts `_ from Rob Simmon and this `more technical paper `_. Seaborn makes it easy to select and use color palettes that are suited to the kind of data you are working with and the goals you have in visualizing it.

In [ ]:
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
np.random.seed(sum(map(ord, "palettes")))
Building color palettes with :func:`color_palette` -------------------------------------------------- To grab the current color cycle, call the :func:`color_palette` function with no arguments. This just returns a list of r, g, b tuples:

In [ ]:
current_palette = sns.color_palette()
current_palette
Seaborn has a small function to visualize a palette, which is useful for documentation and possibly for when you are choosing colors for your own plots. The default color scheme is based on the matplotlib default while aiming to be a bit more pleasant to look at.

In [ ]:
sns.palplot(current_palette)
There are six variations of the default theme, called ``pastel``, ``bold``, ``muted``, ``deep``, ``dark``, and ``colorblind``. It's also easy to get evenly spaced hues in the `husl` or `hls` color spaces. The former is preferred for its perceptual uniformity, although the individual colors can be relatively less attractive than their brighter versions in the latter.

In [ ]:
sns.palplot(sns.color_palette("husl", 8))

In [ ]:
sns.palplot(sns.color_palette("hls", 8))
You can also use the name of any matplotlib colormap, and the palette will return evenly-spaced samples from points near the extremes.

In [ ]:
sns.palplot(sns.color_palette("coolwarm", 7))
Palettes can be broadly categorized as *diverging* (as is the palette above), *sequential*, or *qualitative*. Diverging palettes are useful when the data has a natural, meaninfgul break-point (as with correlation values, which are spread around zero). Sequential palettes are better when the data range from "low" to "high" values.

In [ ]:
sns.palplot(sns.color_palette("RdPu_r", 8))
Categorial data is best represented by a qualitative palette. Seaborn fixes some problems inherent in the way matplotlib deals with the qualitative palettes from the `colorbrewer `_ package, but they behave a little differently from other seaborn palettes. If you request more colors than exist for a given qualitative palette, the colors will cycle:

In [ ]:
sns.palplot(sns.color_palette("Set2", 10))
Finally, you can just pass in a list of color codes to specify a custom palette.

In [ ]:
flatui = ["#9b59b6", "#3498db", "#95a5a6", "#e74c3c", "#34495e", "#2ecc71"]
sns.palplot(sns.color_palette(flatui))
.. _cubehelix_palettes: Well-behaved sequential palettes with :func:`cubehelix_palette` --------------------------------------------------------------- The `cubehelix `_ color palette system makes sequential palettes with a linear increase or decrease in brightness and some variation in hue. This means that the information in your colormap will be preserved when converted to black and white (for printing) or when viewed by a colorblind individual. Matplotlib has the default cubehelix version built into it:

In [ ]:
sns.palplot(sns.color_palette("cubehelix", 8))
Seaborn adds an interface to the cubehelix *system* so that you can make a variety of palettes that all have a well-behaved linear brightness ramp. The default palette returned by the seaborn :func:`cubehelix_palette` function is a bit different from the matplotlib default in that it does not rotate as far around the hue wheel or cover as wide a range of intensities. It also reverses the order so that more important values are darker:

In [ ]:
sns.palplot(sns.cubehelix_palette(8))
Other arguments to :func:`cubehelix_palette` control how the palette looks. The two main things you'll change are the ``start`` (a value between 0 and 3) and ``rot``, or number of rotations (an arbitrary value, but probably within -1 and 1),

In [ ]:
sns.palplot(sns.cubehelix_palette(8, start=.5, rot=-.75))
You can also control how dark and light the endpoints are and even reverse the ramp:

In [ ]:
sns.palplot(sns.cubehelix_palette(8, start=2, rot=0, dark=0, light=.95, reverse=True))
By default you just get a list of colors, like any other seaborn palette, but you can also return the palette as a colormap object that can be passed to matplotlib functions using ``as_cmap=True``.

In [ ]:
sample = np.random.multivariate_normal([0, 0], [[1, -.5], [-.5, 1]], size=300)
cmap = sns.cubehelix_palette(light=1, as_cmap=True)
f, ax = plt.subplots(figsize=(6, 6))
plt.hexbin(*sample.T, gridsize=17, cmap=cmap);
Creating custom palettes with :func:`blend_palette` and :func:`dark_palette` ---------------------------------------------------------------------------- Two other functions allow you to create custom palettes. The first takes a color and creates a blend to it from a very dark gray.

In [ ]:
sns.palplot(sns.dark_palette("MediumPurple"))
Note that the interpolation that is done behind the scenes is not currently performed in a color space that is compatible with human perception, so the increments of color in these palettes will not necessarily appear uniform.

In [ ]:
sns.palplot(sns.dark_palette("skyblue", 8, reverse=True))
This function can also return a colormap object:

In [ ]:
pal = sns.dark_palette("palegreen", as_cmap=True)
plt.figure(figsize=(6, 6))
sns.kdeplot(sample, cmap=pal);
There's a related trick embedded in palette production that allows you to specify the name of a sequential ColorBrewer palette with a `"_d"` suffix. This will create a palette that is harmonious with the base palette, but using colors that are dark enough to draw line or contour plots.

In [ ]:
sns.palplot(sns.color_palette("BuPu_d"))
A more general function for making custom palettes is :func:`blend_palette`, which interpolates between an arbitrary number of seed points. You could use this to make your own diverging palette:

In [ ]:
sns.palplot(sns.blend_palette(["mediumseagreen", "ghostwhite", "#4168B7"], 9))
To create a sequential palette along a saturation scale (using :func:`desaturate`):

In [ ]:
sns.palplot(sns.blend_palette([sns.desaturate("#009B76", 0), "#009B76"], 5))
Or to make an ordered palette that can color large patches, like a boxplot:

In [ ]:
sns.palplot(sns.blend_palette(["seagreen", "lightblue"]));
Using palettes in seaborn functions ----------------------------------- Any seaborn function that draws plots with multiple color is using :func:`color_palette` behind the scenes, and will accept a palette for the ``color`` or ``palette`` argument in any of the ways shown above:

In [ ]:
gammas = sns.load_dataset("gammas")
sns.tsplot(gammas, "timepoint", "subject", "ROI", "BOLD signal", color="muted");

In [ ]:
tips = sns.load_dataset("tips")
pal = sns.blend_palette(["seagreen", "lightblue"], 4)
sns.violinplot(tips.total_bill, tips.day, color=pal);

In [ ]:
sns.factorplot("day", "total_bill", hue="smoker", data=tips, kind="box", palette="OrRd");

In [ ]:
attend = sns.load_dataset("attention")
sns.factorplot("solutions", "score",
               hue="subject", col="attention",
               data=attend, ci=None,
               legend=False, palette="Paired");
Changing default palettes with :func:`set_palette` -------------------------------------------------- The :func:`color_palette` function has a companion called :func:`set_palette`. The relationship between them is similar to the pairs covered in the :ref:`aesthetics tutorial `. :func:`set_palette` accepts the same arguments as :func:`color_palette`, but it changes the default matplotlib parameters so that the palette is used for all plots:

In [ ]:
def sinplot(flip=1):
    x = np.linspace(0, 14, 100)
    for i in range(1, 7):
        plt.plot(x, np.sin(x + i * .5) * (7 - i) * flip)

In [ ]:
sns.set_palette("husl")
sinplot()
The :func:`color_palette` function can also be used in a ``with`` statement to temporarily change the color palette:

In [ ]:
with sns.color_palette("PuBuGn_d"):
    sinplot()

In [ ]: