0

I am trying to visualize this graph with a lineplot, but the legend is not working correctly as you can see in the image below.

The problems are three:

  1. two rectangles appear in the second and fourth positions
  2. the legend only show the black, the blue, and the red lines
  3. the three lines above mentioned do not correspond to those in the code (you can obeserve it in the image)

Did someone face the same problem? Who can help me?

var = 'eta_contraente'
target = 'target_accettazione'

DF = df_pred[[var,'target_accettazione','prediction_ret_1', 'prediction_ret_2',   'prediction_ret_3','prediction_ret_4_no_crawler']]

DF['pred_decili'] = pd.qcut(DF[var], list(np.linspace(0, 1, n)))

fig=plt.figure(figsize=(8, 5))
ax = fig.add_subplot(111)

mean_val = DF.groupby("pred_decili").mean().reset_index()
sns.lineplot(x=mean_val.index, y= target, 
             data=mean_val,  marker='s', color = 'black')

sns.lineplot(x=mean_val.index, y= "prediction_ret_1", 
             data=mean_val,  marker='s', color = 'blue')

sns.lineplot(x=mean_val.index, y= 'prediction_ret_2', 
             data=mean_val, marker='s', color = 'red')

sns.lineplot(x=mean_val.index, y= "prediction_ret_3", 
             data=mean_val,  marker='s', color = 'yellow')

sns.lineplot(x=mean_val.index, y= 'prediction_ret_4_no_crawler', 
             data=mean_val,  marker='s', color = 'green')

ax.set_xticks(mean_val.index)
ax.set_xticklabels(mean_val[var].round(), rotation = 60)

ax.legend([ 'black line', "blue line", "red line","yellow line","green line" ], loc='lower right', fontsize = 14);

enter image description here

Please, try to suggest which there is a problem in the code, or whether it is due to the version of matplotlib or pandas

1 Answer 1

0

Normally, matplotlib needs a label= for each element you want to show in the legend. Seaborn is a bit more complicated, as it creates more complex elements. E.g. a line plot can automatically include a stroke indicating a confidence interval (when multiple y values correspond to the same x value). In order not to have too many elements in the legend, seaborn often tries to combine.

In this case, you can just add label= to the line plot.

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

mean_val = pd.DataFrame({'col1': np.random.rand(8),
                         'col2': np.random.rand(8),
                         'col3': np.random.rand(8)})

ax = sns.lineplot(x=mean_val.index, y="col1",
                  data=mean_val, marker='s', color='black', label='black line')
sns.lineplot(x=mean_val.index, y="col2",
             data=mean_val, marker='s', color='blue', label='blue line', ax=ax)
sns.lineplot(x=mean_val.index, y="col3",
             data=mean_val, marker='s', color='red', label='red line', ax=ax)
ax.legend()
plt.show()

adding label to get a legend for sns.lineplot

However, the recommended way is to convert the dataframe to long form, and work with hue.

# rename the columns to the names you want to see in the legend
mean_val = mean_val.rename(columns={'col1': 'black line', 'col2': 'blue line', 'col3': 'red line'})
# convert the dataframe to long form (keeping the index as a column)
mean_val_long = mean_val.reset_index().melt(id_vars='index', var_name='line type', value_name='value')

# draw the lines in one go, using hue and a palette; the legend will be created automatically
ax = sns.lineplot(x='index', y="value", hue='line type',
                  data=mean_val_long, marker='s', palette=['black', 'blue', 'red'])
plt.show()

converting the dataframe to long form to automatically get a legend

Not the answer you're looking for? Browse other questions tagged or ask your own question.