Search code examples
pythonregressionseabornlegendlmplot

How to avoid regression line truncation in zoomed-out lmplot?


I experience 2 problems with this plot:

  1. I tried to add in other features to my code, however the regression lines remain truncated in the lmplot().
  2. When I add the settings for the legend, another legend is added at the bottom left. However, the setting does move the original legend to the outside of my plots.

Here is my code:

g = sns.lmplot(x="fico", y="int.rate", col="not.fully.paid", data=loans, hue = 'credit.policy', palette = 'Set1', truncate = False, scatter_kws={"s": 10}, legend_out = True)

g.set(xlim = (550, 850))
g.set(ylim = (0, 0.25))

g.fig.tight_layout()
plt.legend(bbox_to_anchor=(1.3, 0), loc='upper right')

Link to my plot: github link


Solution

  • lmplot() has an option truncate= which defaults to True, i.e. truncate the regression lines to the first and last points. truncate=False will extend them till they touch the x limits at the time of drawing. You don't want the default xlims, and lmplot() doesn't seem to provide a way to set these limits beforehand. An approach could be to set the default x-margins very high (via rcParams) and thereafter shrinking the x-limits back.

    Moving a legend is quite difficult. Often the old one needs to be removed and a new one created. In this case, you can set legend=False during the creation. And create it afterwards (some legends are more complicated and require many manual parameters).

    A legend can be created using an ax, in this case the ax of the last subplot. The position is given in "axes coordinates", going from 0,0 in the bottom left corner to 1,1 in the upper right corner. Coordinates slightly outside that range will be just outside the main plot area. When a position is given, the loc= parameter tells which corner of the legend is involved. So loc='upper left' is the upper left corner of the legend.

    Here is some example code:

    import matplotlib.pyplot as plt
    import seaborn as sns
    import matplotlib as mpl
    
    sns.set_theme(style="ticks")
    tips = sns.load_dataset('tips')
    mpl.rcParams['axes.xmargin'] = 0.5  # set very wide margins: 50% of the actual range
    g = sns.lmplot(x="total_bill", y="tip", col="smoker", hue="time", data=tips, truncate=False, legend=False)
    mpl.rcParams['axes.xmargin'] = 0.05 # set the margins back to the default
    # add the legend just outside the last subplot
    g.fig.axes[-1].legend(bbox_to_anchor=(1.02, 1.01), loc='upper left', title='Time')
    g.set(xlim = (0, 80)) # set the limits to the desired ones
    plt.tight_layout() # fit labels and legend
    plt.show()
    

    lmplot