Customizing annotation with Seaborn's FacetGrid

自闭症网瘾萝莉.ら 提交于 2020-08-21 06:08:01

问题


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)

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?


回答1:


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}')

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}')



来源:https://stackoverflow.com/questions/31632372/customizing-annotation-with-seaborns-facetgrid

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!