pythonpython-3.xmatplotlibseabornlegend

Seaborn - Legend not getting displayed on twinx()


I am trying to plot a data on 2 y-axis by using twinx(). The issue is that the legend on the axis - twinx() is not getting displayed. Below is the image that has the expected result which was generated using seaborn lineplot and matplotlib plot

the code used for expected result is as below:

df_plot = DF02.query('Make == "Acura"')
Fig = plt.figure()
ax1 = Fig.add_axes([0, 0, 1, 1])
ax2 = ax1.twinx()

# Drawing a line plot
sns.lineplot(data = df_plot,
             x = 'Year',
             y = 'highway MPG',
             hue = 'Model',
             palette = 'rocket',
             style = 'Model',
             markers = True,
             dashes = False,
             ax = ax1)

# Drawing line plot on ax2 using matplotlib
ax2.plot(df_plot['Year'],
         df_plot['avg highway MPG'],
         marker = '*',
         label = 'avg highway MPG')

# Set x-axis and y-axis ticks
xticks = np.arange(1990, 2021, 2)
ax1.set_xticks(xticks)

yticks = np.arange(10, 41, 2)
ax1.set_yticks(yticks)

ax2.set_yticks(yticks)
ax2.axes.get_yaxis().set_visible(False)

# Change name of plot title
ax1.set_title("Line Plot in Seaborn", fontdict = {'weight': 'bold'})

# Change x and y axis titles
ax1.set_xlabel('Year')
ax1.set_ylabel('Highway Fuel Economy [MPG]')

# Placing the legend
ax1.legend(title = "Vehicle Model\n", loc = 'center right', bbox_to_anchor = (1.3, 0.5))
ax2.legend(title = 'Legend', loc = 'upper right', bbox_to_anchor = (1, 1))

# Enabling the grid
ax1.grid(ls = '--', color = 'lightgrey')

However when plotted using seaborn, the legend does not appear as expected. Actual result

Code used in actual result is as below:

df_plot = DF02.query('Make == "Acura"')
Fig = plt.figure()
ax1 = Fig.add_axes([0, 0, 1, 1])
ax2 = ax1.twinx()

# Drawing a line plot
sns.lineplot(data = df_plot,
             x = 'Year',
             y = 'highway MPG',
             hue = 'Model',
             palette = 'rocket',
             style = 'Model',
             markers = True,
             dashes = False,
             ax = ax1)

sns.lineplot(data = df_plot,
             x = 'Year',
             y = 'avg highway MPG',
             ax = ax2)

# Set x-axis and y-axis ticks
xticks = np.arange(1990, 2021, 2)
ax1.set_xticks(xticks)

yticks = np.arange(10, 41, 2)
ax1.set_yticks(yticks)

ax2.set_yticks(yticks)
ax2.axes.get_yaxis().set_visible(False)

# Change name of plot title
ax1.set_title("Line Plot in Seaborn", fontdict = {'weight': 'bold'})

# Change x and y axis titles
ax1.set_xlabel('Year')
ax1.set_ylabel('Highway Fuel Economy [MPG]')

# Placing the legend
ax1.legend(title = "Vehicle Model\n", loc = 'center right', bbox_to_anchor = (1.3, 0.5))
ax2.legend(loc = 'upper right', bbox_to_anchor = (1, 1))

# Enabling the grid
ax1.grid(ls = '--', color = 'lightgrey')

Can anyone please suggest how to get the result similar to expected result by using seaborn on both axes ax1 and ax2?


Solution

  • The call sns.lineplot(data=df_plot, x='Year', y='avg highway MPG', ax=ax2) doesn't generate a legend entry as there is only one line drawn (there is no 'hue' parameter). You can add a label: sns.lineplot(..., label='avg highway MPG') to tell matplotlib what you want to see in the legend.

    To change legend parameters, ax2.legend(...) often doesn't work with plots created with seaborn. Instead, in seaborn it is recommended sns.move_legend(...) to change titles and other legend properties.

    Here is a minimal example, first to mimic the original code:

    import matplotlib.pyplot as plt
    import seaborn as sns
    
    mpg = sns.load_dataset('mpg')
    ax2 = sns.lineplot(mpg, x='model_year', y='mpg')
    ax2.legend(loc='upper right', bbox_to_anchor=(1, 1))
    

    This gives a warning No artists with labels found to put in legend. and creates an empty legend:

    empty legend for sns.lineplot without hue

    Adding a label creates a legend:

    import matplotlib.pyplot as plt
    import seaborn as sns
    
    mpg = sns.load_dataset('mpg')
    ax2 = sns.lineplot(mpg, x='model_year', y='mpg', label='miles per gallon')
    plt.show()
    

    sns.lineplot with label for legend

    You can move the legend and/or change other properties via sns.move_legend(ax2, loc='upper right').