Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
706 views
in Technique[技术] by (71.8m points)

python - How to put the legend on first subplot of seaborn.FacetGrid?

I have a pandas DataFrame df which I visualize with subplots of a seaborn.barplot. My problem is that I want to move my legend inside one of the subplots.

To create subplots based on a condition (in my case Area), I use seaborn.FacetGrid. This is the code I use:

import matplotlib.pyplot as plt
import matplotlib
import seaborn as sns
# .. load data
grid = sns.FacetGrid(df, col="Area", col_order=['F1','F2','F3'])
bp = grid.map(sns.barplot,'Param','Time','Method')
bp.add_legend()
bp.set_titles("{col_name}")
bp.set_ylabels("Time (s)")
bp.set_xlabels("Number")
sns.plt.show()

Which generates this plot:

barplot-all

You see that the legend here is totally at the right, but I would like to have it inside one of the plots (for example the left one) since my original data labels are quite long and the legend occupies too much space. This is the example for only 1 plot where the legend is inside the plot:

barplot1

and the code:

mask = df['Area']=='F3'
ax=sns.barplot(x='Param',y='Time',hue='Method',data=df[mask])
sns.plt.show()

Test 1: I tried the example of an answer where they have the legend in one of the subplots:

grid = sns.FacetGrid(df, col="Area", col_order=['F1','F2','F3'])
bp = grid.map(sns.barplot,'Param','Time','Method')
Ax = bp.axes[0]
Boxes = [item for item in Ax.get_children()
     if isinstance(item, matplotlib.patches.Rectangle)][:-1]
legend_labels  = ['So1', 'So2', 'So3', 'So4', 'So5']
# Create the legend patches
legend_patches = [matplotlib.patches.Patch(color=C, label=L) for
              C, L in zip([item.get_facecolor() for item in Boxes],
                          legend_labels)]

# Plot the legend
plt.legend(legend_patches)    
sns.plt.show()

Note that I changed plt.legend(handles=legend_patches) did not work for me therefore I use plt.legend(legend_patches) as commented in this answer. The result however is:

bar test with legend in 3rd

As you see the legend is in the third subplot and neither the colors nor labels match.


Test 2:

Finally I tried to create a subplot with a column wrap of 2 (col_wrap=2) with the idea of having the legend in the right-bottom square:

grid = sns.FacetGrid(df, col="MapPubName", col_order=['F1','F2','F3'],col_wrap=2)

but this also results in the legend being at the right:

barplot 2cols


Question: How can I get the legend inside the first subplot? Or how can I move the legend to anywhere in the grid?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You can set the legend on the specific axes you want, by using grid.axes[i][j].legend()

For your case of a 1 row, 3 column grid, you want to set grid.axes[0][0].legend() to plot on the left hand side.

Here's a simple example derived from your code, but changed to account for the sample dataset.

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

df = sns.load_dataset("tips")

grid = sns.FacetGrid(df, col="day")
bp = grid.map(sns.barplot,"time",'total_bill','sex')

grid.axes[0][0].legend()

bp.set_titles("{col_name}")
bp.set_ylabels("Time (s)")
bp.set_xlabels("Number")
sns.plt.show()

enter image description here


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...