Nathan
Nathan

Reputation: 29

How to change python pyplot legend with 4 legend instead of 2

Thanks for taking time on my question.

I have 2 DataFrame composed of several columns:

df=pd.DataFrame([['A',10, 22], ['A',12, 15], ['A',0, 2], ['A', 20, 25], ['A', 5, 5], ['A',12, 11], ['B', 0 ,0], ['B', 9 ,0], ['B', 8 ,50], ['B', 0 ,0], ['B', 18 ,5], ['B', 7 ,6],['C', 10 ,11], ['C', 9 ,10], ['C', 8 ,2], ['C', 6 ,2], ['C', 8 ,5], ['C', 6 ,8]],
         columns=['Name', 'Value_01','Value_02'])
df_agreement=pd.DataFrame([['A', '<66%', '>80'],['B', '>80%', '>66% & <80%'], ['C', '<66%', '<66%']], columns=['Name', 'Agreement_01', 'Agreement_02'])

my goal is to create boxplot for this DataFrame, with ['Value_01', 'Value_02'] as values and 'Name' as x-values. To do so, I perform a sns boxplot with the following code:

fig = plt.figure()
# Change seaborn plot size
fig.set_size_inches(60, 40)
plt.xticks(rotation=70)
plt.yticks(fontsize=40)
df_02=pd.melt(df, id_vars=['Name'],value_vars=['Value_01', 'Value_02'])
bp=sns.boxplot(x='Name',y='value',hue="variable",showfliers=True, data=df_02,showmeans=True,meanprops={"marker": "+", 
                       "markeredgecolor": "black", 
                       "markersize": "20"})
bp.set_xlabel("Name", fontsize=45)
bp.set_ylabel('Value', fontsize=45)
bp.legend(handles=bp.legend_.legendHandles, labels=['V_01', 'V_02'])

Okay this part works, I do have 6 boxplots, two for each name.

What is becoming tricky is that I want to use the df_agreement to change the color of my boxplots, regarding it is <66% or not. So I added this in my code:

list_color_1=[]
list_color_2=[]
for i in range(0, len(df_agreement)):
    name=df_agreement.loc[i,'Name']
    if df_agreement.loc[i,'Agreement_01']=="<66%":
        list_color_1.append(i*2)
    if df_agreement.loc[i,'Agreement_02']=="<66%":
        list_color_2.append(i*2+1)
for k in list_color_1:
    mybox = bp.artists[k]
    # Change the appearance of that box
    mybox.set_facecolor("#D1DBE6") #facecolor is the inside color of the boxplot
    mybox.set_edgecolor('black') #edgecolor is the line color of the box
    mybox.set_linewidth(2)
for k in list_color_2:
    mybox = bp.artists[k]
    # Change the appearance of that box
    mybox.set_facecolor("#EFDBD1") #facecolor is the inside color of the boxplot
    mybox.set_edgecolor('black') #edgecolor is the line color of the box
    mybox.set_linewidth(2)

it works well, I have my boxplots that have changed regarding the value on df_agreement. But, unfortunatelly, I would like also to change the legend with ["V_01", "V_02", "V_01 with less 66% agreement", "V_02 with less 66% agreement"], and obviously with the corresponding color in the legend.

Would you have an idea to perform that ?

Thank you very much ! :)

Upvotes: 0

Views: 40

Answers (1)

JohanC
JohanC

Reputation: 80279

You could add custom legend elements, extending the list of handles. Here is an example.

handles, labels = bp.get_legend_handles_labels()
new_handles = handles + [plt.Rectangle((0, 0), 0, 0, facecolor="#D1DBE6", edgecolor='black', linewidth=2),
                         plt.Rectangle((0, 0), 0, 0, facecolor="#EFDBD1", edgecolor='black', linewidth=2)]
bp.legend(handles=new_handles,
          labels=['V_01', 'V_02', "V_01 with less\n than 66% agreement", "V_02 with less\n than 66% agreement"])

adding a custom legend

Upvotes: 1

Related Questions