Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

FacetGrid Legend empty

I'm trying to create a seaborn FacetGrid to show the transition probabilities between clusters in some data I have. The data has a bunch of subjects and 4 clusters (so that each subject has 16 data points, one for each pair of old and new clusters). Because these are probabilities, all values that have the same old cluster (for each subject) sum to 1. I would like to show this data using a FacetGrid pointplot (or stacked barplot, but that doesn't seem possible with seaborn), such that each old cluster is a separate column, new cluster is a separate hue, and each facet shows subject vs. probability.

Here's code to generate a toy DataFrame with the same features as mine, as well as code for the facetgrid I'd like to make. However, when I do all this, the legend is empty.

df,index = [],0
for subj in [1,2]:
    for i,j in itertools.product(range(4),range(4)):
        df.append(pd.DataFrame(index=[index],data=dict(subject=subj,old=i,new=j,prob=[.23,.24,.26,.27][j])))
        index+=1
df = pd.concat(df)
g = sns.FacetGrid(df,col='old',hue='new',margin_titles=False,legend_out=True)
g.map(sns.pointplot,'subject','prob',join=False)
g.add_legend()

Looking at g._legend_data shows that it's empty and each of the axes get_legend_handles_labels() functions returns nothing. What's going on?

I can't post an image of my plot because I don't have 10 reputation; the name of the legend appears over on the far right, but nothing is in it...

EDIT: Additionally, I'd like to dodge the values a little, but g.map(sns.pointplot,'subject','prob',join=False,dodge=.1) looks the exact same as above, for a variety of different dodge values...

EDIT 2: So it appears that using sns.factorplot, instead of FacetGrid, both the legend and the dodge work. The only thing I can't do using sns.factorplot is rotate the xtick labels, but that's not working with col_wrap in Facet Grid anyway... Why is FacetGrid having this problem?

like image 966
Bill Broderick Avatar asked Mar 11 '15 16:03

Bill Broderick


People also ask

What is the purpose of FacetGrid?

This is achieved using Seaborn's FacetGrid function. This allows us to create a grid, on which we can map many other types of plots with minimal code, especially compared to using matplotlib.

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.

How do you change the legend in Seaborn?

Changing the location of Seaborn legends We use matplotlib. pyplot. legend() function from matplotlib library and pass the bbox_to_anchor parameter which allows us to pass an (x,y) tuple with the required offset for changing the location of the seaborn legends.


1 Answers

As you note, factorplot provides an easier interface to using pointplot and FacetGrid together. The reason the legend and dodging doesn't work the original way you're doing it is that setting hue in FacetGrid and setting it in pointplot are different. When you call pointplot without a hue variable, it doesn't know how to dodge, and it doesn't think it needs to add any legend data.

Option one would be to move where you use the hue variable:

g = sns.FacetGrid(df,col='old', col_wrap=2)
g.map(sns.pointplot, 'subject', 'prob', 'new', dodge=.1, join=False)
g.add_legend()

enter image description here

But I can't think of any reason to use FacetGrid this way instead of just using factorplot:

g = sns.factorplot(x="subject", y="prob", hue="new", data=df,
               col="old", col_wrap=2, size=3,
               dodge=.1, join=False)

enter image description here

So the only remaining issue is rotating the x axis tick labels. factorplot returns a FacetGrid instance, so in principle it should be easy to use further FacetGrid methods to tweak the plot. I suspect the problem you're getting is this bug, which will be fixed in the next release. In the meantime, you can work around it like so:

g = sns.factorplot(x="subject", y="prob", hue="new", data=df,
                   col="old", col_wrap=2, size=3,
                   dodge=.1, join=False)
for ax in g.axes:
    plt.setp(ax.get_xticklabels(), rotation=45)

enter image description here

like image 128
mwaskom Avatar answered Oct 02 '22 13:10

mwaskom