seaborn in jupyter notebook: why does sns.despine() work for lmplot but not regplot?

Question:

Jupyter notebook, using Python 3:

import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline
sns.despine()

then

snstest1 = sns.regplot(x="foo", y="bar", data=my_data)

shows a plot with the unwanted border box (i.e., sns.despine() doesn’t seem to have affected it).

but:

snstest2 = sns.lmplot(x="foo", y="bar", data=my_data)

shows a plot with the unwanted border box correctly removed.

The only documentation I can find that seems to bear directly on this is the following, from the api docs for regplot:

Understanding the difference between regplot() and lmplot() can be a
bit tricky. In fact, they are closely related, as lmplot() uses
regplot() internally and takes most of its parameters. However,
regplot() is an axes-level function, so it draws directly onto an axes
(either the currently active axes or the one provided by the ax
parameter), while lmplot() is a figure-level function and creates its
own figure, which is managed through a FacetGrid. This has a few
consequences, namely that regplot() can happily coexist in a figure
with other kinds of plots and will follow the global matplotlib color
cycle. In contrast, lmplot() needs to occupy an entire figure, and the
size and color cycle are controlled through function parameters,
ignoring the global defaults.

But I don’t fully understand the difference between a “figure” and an “axis.” The best guess I can make without knowing the underlying model here is that when these weird global-state-mutating functions built into Seaborn, like despine and (?) set_palette and such, are active, only “figures,” not “axes,” check that state before rendering? But if that’s so, how would I get something that generates an “axis” to plot in accordance with what I’ve requested?

Asked By: Paul Gowder

||

Answers:

In short: Call sns.despine after your plotting function.

The longer version:

lmplot creates its own figure. But it does not need despine. It will do it automatically, even without calling sns.despine.

import matplotlib.pyplot as plt
import seaborn as sns

tips = sns.load_dataset("tips")
g = sns.lmplot(x="total_bill", y="tip", data=tips)

plt.show()

enter image description here

This is the reason the code from the question actually seems to work.
However, what is really happening is that if you call sns.despine before any figure is created, it will act on a newly created figure. The code from the question is hence creating two figures. One, which is empty, but also is “despined” and then one which is the lmplot figure and which is “despined” because every lmplot is despined by default.

A regplot is instead created in an axes of a matplotlib figure. If no figure or axes is provided, it will create a new one. This means that sns.despine needs to know which axes to despine. If you call it before anything else, there will again be two figures: One, which is empty, but also is “despined” and then one which is the regplot figure. This figures axes are not “despined”, because noone told them so.

So the idea is of course to call sns.despine after creating the plot. You may specify which figure or axes to despine as argument (sns.despine(ax=ax))

import matplotlib.pyplot as plt
import seaborn as sns

tips = sns.load_dataset("tips")
ax = sns.regplot(x="total_bill", y="tip", data=tips)
sns.despine(ax=ax)

plt.show()

but if you only have a single subplot that wouldn’t even be necessary. Hence

tips = sns.load_dataset("tips")
sns.regplot(x="total_bill", y="tip", data=tips)
sns.despine()

will work equally well and produce

enter image description here