Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to split seaborn legend into multiple columns?

I use a relplot with different hue and style and would like to show the respective legend entries besides instead of below each other.

So currently I get a legend like this:

relplot legend with hue and style labels below each other

Instead I would like to have a single legend looking something like this:

relplot legend with hue and style labels besides each other

How can this be done?

I tried setting the following but that had no effect:

plot._legend
leg._ncol = 2
leg.handleheight = 1  # restricting the height

Minimal working example to solve this problem:

import pandas as pd
import seaborn as sns

columns = ['category1', 'category2', 'category3', 'time', 'value']

data = [['content1', 'other1', 'critera1', 0, 0.1], ['content1', 'other1', 'critera1', 1, 0.4], ['content1', 'other1', 'critera1', 2, 0.7], ['content2', 'other1', 'critera1', 0, 0.2], ['content2', 'other1', 'critera1', 1, 0.6], ['content2', 'other1', 'critera1', 2, 0.8], ['content1', 'other2', 'critera1', 0, 0.0], ['content1', 'other2', 'critera1', 1, 0.2], ['content1', 'other2', 'critera1', 2, 0.8], ['content2', 'other2', 'critera1', 0, 0.3], ['content2', 'other2', 'critera1', 1, 0.6], ['content2', 'other2', 'critera1', 2, 0.5], [
    'content1', 'other1', 'critera2', 0, 0.1], ['content1', 'other1', 'critera2', 1, 0.4], ['content1', 'other1', 'critera2', 2, 0.7], ['content2', 'other1', 'critera2', 0, 0.2], ['content2', 'other1', 'critera2', 1, 0.6], ['content2', 'other1', 'critera2', 2, 0.8], ['content1', 'other2', 'critera2', 0, 0.0], ['content1', 'other2', 'critera2', 1, 0.2], ['content1', 'other2', 'critera2', 2, 0.8], ['content2', 'other2', 'critera2', 0, 0.3], ['content2', 'other2', 'critera2', 1, 0.6], ['content2', 'other2', 'critera2', 2, 0.5], ]

df = pd.DataFrame(data, columns=columns)

plot = sns.relplot(x='time', y='value', col='category3', hue='category1', style='category2', kind="line", col_wrap=2, data=df)

leg = plot._legend
leg.set_bbox_to_anchor((0.5, 1.3, 0, 0))
leg._loc = 9

minimal working example output


like image 312
Spenhouet Avatar asked Jun 13 '19 07:06

Spenhouet


People also ask

How do you plot multiple variables in Seaborn?

In Seaborn, we will plot multiple graphs in a single window in two ways. First with the help of Facetgrid() function and other by implicit with the help of matplotlib. data: Tidy dataframe where each column is a variable and each row is an observation.

How do you move legends in Seaborn?

With Seaborn's move_legend() function, we can easily change the position to common legend places. For example, to move the legend to lower right of Seaborn plot we specify “lower right” to move_legend() function. Note now the legend is moved to the lower left corner of the plot.

How do you put two Seaborn plots together?

To create two graphs, we can use nrows=1, ncols=2 with figure size (7, 7). Create a data frame with keys, col1 and col2, using Pandas. Use countplot() to show the counts of observations in each categorical bin using bars. Adjust the padding between and around the subplots.


1 Answers

Since you seem to want to place the legend above the plots, I would instruct seaborn to not reserve space on the right for the legend using legend_out=False. Then it's just a matter of getting the handles and labels created by seaborn, and generate a new legend using ncol=2. Note that this will only work well if you have the same number of elements in both columns, otherwise things will get messy.

plot = sns.relplot(x='time', y='value', col='category3', hue='category1', style='category2', kind="line", col_wrap=2, data=df, facet_kws=dict(legend_out=False))
h,l = plot.axes[0].get_legend_handles_labels()
plot.axes[0].legend_.remove()
plot.fig.legend(h,l, ncol=2) # you can specify any location parameter you want here
like image 129
Diziet Asahi Avatar answered Sep 17 '22 15:09

Diziet Asahi