'Combine seaborn legends with histplot

I've got four separate subplots below. the figure is as intended and legend is fine. But I'm including a separate line to each subplot and want to include this in the legend. However, I can't seem to include it. I've tried a few approaches and nothing seems to work.

Option 1 doesn't include the line, while option 2 does but the ordering is backwards and not accurate.

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

df = pd.DataFrame(np.random.randint(0,4,size=(100, 4)), columns=list('ABCD'))
df['String'] = np.random.choice(['yes','no','maybe'],len(df))
df['String'] = pd.Categorical(df['String'], ['yes','no','maybe'])


def fig(df):

    fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2,2, figsize = (8,10))

    ax1 = sns.histplot(data = df, 
             x = 'A', 
             hue = 'String',
             multiple = 'fill', 
             ax = ax1
             )

    ax2 = sns.histplot(data = df, 
             x = 'B', 
             hue = 'String',
             multiple = 'fill', 
             ax = ax2
             )

    ax3 = sns.histplot(data = df, 
             x = 'C', 
             hue = 'String',
             multiple = 'fill', 
             ax = ax3
             )

    ax4 = sns.histplot(data = df, 
             x = 'D', 
             hue = 'String',
             multiple = 'fill', 
             ax = ax4
             )

    ax1.axhline(0.2, color = 'b', linestyle = '--', label = 'avg')
    ax2.axhline(0.5, color = 'b', linestyle = '--', label = 'avg')
    ax3.axhline(0.8, color = 'b', linestyle = '--', label = 'avg')
    ax4.axhline(0.9, color = 'b', linestyle = '--', label = 'avg')

    # option 1
    #legend = ax1.get_legend()
    #handles = legend.legendHandles
    #legend.remove()
    #ax1.legend(handles, ['yes','no','maybe', 'avg'])

    # option 2
    h,labels = ax1.get_legend_handles_labels()
    h = ['yes','no','maybe', 'avg']

    ax1.legend(h,loc=2)

fig(df)


Solution 1:[1]

You can do this by using the method in option 1 to get the legends of the horizontal lines without erasing the legends, and then combining each of them. The code only adjusts the first legend, so you can modify the other legends according to this example.

# option 1
legend = ax1.get_legend()
print(legend.get_texts())
handles = legend.legendHandles
print(handles)
h,l = ax1.get_legend_handles_labels()
print(l)
print(h)
l = ['yes','no','maybe','avg']
ax1.legend(handles+h, l, title='String')

enter image description here

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1