Set axis offset dynamically on seaborn.despine()

Viewed 763

I wanted to calculate the axis offset for seaborn.despine() dynamically. It should stick to the 0 value of my matplotlib axes. But somehow it seems I have the wrong concept of calculating it.

As I need to set seaborn's offset in points I tried to calculate the image size, and set it into proportion with the x-axis with, but as it can be seen in the small code sample below this doen't work as desired.

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

# Define and use a simple function to label the plot in axes coordinates
def label(x, color, label):
    ax = plt.gca()
    ax.text(0, .2, label, fontweight="bold", color=color,
            ha="left", va="center", transform=ax.transAxes)

# Create sample data
rs = np.random.RandomState(1979)
x = rs.randn(500)
g = np.tile(list("ABCDEFGHIJ"), 50)
df = pd.DataFrame(dict(x=x, g=g))

# Plot
sns.set(style="white", rc={"axes.facecolor": (0, 0, 0, 0)})

pal = sns.color_palette("hls")
# Initialize the FacetGrid object
g = sns.FacetGrid(df, row="g", hue="g", aspect=20, height=0.7, palette=pal)

# Draw the densities in a few steps
g.map(sns.kdeplot, "x", clip_on=False, shade=True, alpha=0.7, lw=2, bw='scott')
g.map(sns.kdeplot, "x", clip_on=False, color="k", lw=1, bw='scott')

g.map(label, "x")

# Set the subplots to overlap
g.fig.subplots_adjust(hspace=-.25)


# calculate offset for left axis
ax = g.axes[0]
ax_size = abs(ax[0].get_xlim()[0]) + ax[0].get_xlim()[1]
fig = g.fig
size = fig.get_size_inches()*fig.dpi
fig_size = size[0]
off = fig_size * ax[0].get_xlim()[0] / ax_size

# Remove axes details that don't play well with overlap
g.set_titles("")
g.set(yticks=[])
g.despine(bottom=False, left=False, offset={'left':off}); # set offset

the plot looks like this: Plot

as it can be seen, the axis is way off the zero-value. Anyone an idea how to get this right?

Thanks in advance,

Exi

1 Answers

Nice MWE. There are some issues with how specifications in points are handled in matplotlib and I think the problem is potentially related to them. Try to avoid any specification in points for the time being.

Seaborn's 'despine' forces the use of points; however, we can fall back to the corresponding matplotlib function which is more flexible, and even has a convenient shorthand for centering the spines on the data origin.

for ax in g.axes.ravel():
    ax.spines['left'].set_position('zero')

enter image description here

Also, I recommend you read up on transformations in matplotlib, then you don't need to figure them out by hand as you did when computing off.

Related