Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Customizing annotation with Seaborn's FacetGrid

I'm trying to customize some figures with the Seaborn module in Python, but I haven't had luck creating custom labels or annotations. I've got some code that generates the following figure:

plot = sns.FacetGrid(data = data, col = 'bot', margin_titles = True).set_titles('Human', 'Bot')
bins = np.linspace(0, 2000, 15)
plot = plot.map(plt.hist, 'friends_count', color = 'black', lw = 0, bins = bins)
plot.set_axis_labels('Number Following', 'Count')
sns.despine(left = True, bottom = True)

enter image description here

I'd like to do two things: 1. replace the default factor labels, e.g. 'bot = 0.0', with meaningful text, and 2. draw vertical lines at the mean number following for each category.

Here's a self-contained example:

import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt

fake = pd.DataFrame({'val': [1, 2, 2, 3, 3, 2, 1, 1, 2, 3], 'group': [0, 0, 0, 0, 0, 1, 1, 1, 1, 1]})
plot = sns.FacetGrid(data = fake, col = 'group', margin_titles = True).set_titles('zero', 'one')
plot = plot.map(plt.hist, 'val', color = 'black', lw = 0)
sns.despine(left = True, bottom = True)

Anyone know how to customize FacetGrids?

like image 413
Erin Shellman Avatar asked Jul 26 '15 00:07

Erin Shellman


People also ask

What does SNS FacetGrid do?

FacetGrid() : FacetGrid class helps in visualizing distribution of one variable as well as the relationship between multiple variables separately within subsets of your dataset using multiple panels.

How do you plot FacetGrid?

Plotting Small Multiples of Data SubsetsA FacetGrid can be drawn with up to three dimensions − row, col, and hue. The first two have obvious correspondence with the resulting array of axes; think of the hue variable as a third dimension along a depth axis, where different levels are plotted with different colors.

What is Col_wrap?

col_wrapint. “Wrap” the column variable at this width, so that the column facets span multiple rows. Incompatible with a row facet. share{x,y}bool, 'col', or 'row' optional. If true, the facets will share y axes across columns and/or x axes across rows.


1 Answers

A few things about set_titles.

First, the default titles are drawn in the FacetGrid.map method, so if you want to change the titles, you have to call set_titles after plotting, or else they will be overwritten.

Second, if you look at the docstring for the method, it doesn't just take an arbitrary list of titles. It provides a way to change how the title is rendered using the column variable name and value:

template : string
    Template for all titles with the formatting keys {col_var} and
    {col_name} (if using a `col` faceting variable) and/or {row_var}
    and {row_name} (if using a `row` faceting variable).

So the easiest way to have "meaningful text" is to use meaningful data in your dataframe. Take this example with random data:

df = pd.DataFrame({'val': np.random.randn(100),
                   'group': np.repeat([0, 1], 50)})

If you want "group" to be zero and one, you should just change that column, or make a new one:

df["group"] = df["group"].map({0: "zero", 1; "one"})

Then say you don't want to have the variable name in the title, the proper way to use FacetGrid.set_titles would be

g = sns.FacetGrid(data=df, col='group')
g.map(plt.hist, 'val', color='black', lw=0)
g.set_titles('{col_name}')

some bar graphs

If you don't want to change the data you're plotting, then you'll have to set the attributes on the matplotlib axes directly, something like:

for ax, title in zip(g.axes.flat, ['zero', 'one']):
    ax.set_title(title)

Note that this is less preferable to the above method because you have to be very careful about making sure the order of your list is correct and that it isn't going to change, whereas getting the information from the dataframe itself will be much more robust.

To plot the mean, you'll need to create a small function that can be passed to FacetGrid.map. There are multiple examples of how to do this in the tutorial. In this case, it's quite easy:

def vertical_mean_line(x, **kwargs):
    plt.axvline(x.mean(), **kwargs)

Then all you need is to re-plot:

g = sns.FacetGrid(data=df, col='group')
g.map(plt.hist, 'val', color='black', lw=0)
g.map(vertical_mean_line, 'val')
g.set_titles('{col_name}')

some more bar graphs

like image 182
mwaskom Avatar answered Sep 20 '22 22:09

mwaskom