How do I prevent a second plot on an axis from rescaling a seaborn FacetGrid?

68 Views Asked by At

I am trying to overlay a categorical strip plot on top of a categorical violin plot. I plot the violin plot, and then the strip plot, but the axes are rescaled to the strip plot. I would like to keep the original axes from the violin plots.

Here is the code snippet for the violin plot:

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

data = pd.DataFrame.from_dict({
    'y_violin': list(range(16)),
    'y_strip': [8] * 16,
    'x':   [1, 1, 0, 0] * 4,
    'col': [1, 1, 1, 1, 0, 0, 0, 0] * 2,
    'hue': [1] * 8 + [0] * 8,
})

g = sns.catplot(
    kind = 'violin', data = data,
    x = 'x', y = 'y_violin', col = 'col', hue = 'hue',
    inner = 'points', dodge = False,
)

plt.show()

which produces the following image: Violin plot

Then, I try to plot some more points on each axis:

for col, ax in g.axes_dict.items():
    sns.stripplot(
        data = data.loc[data.col == col],
        x = 'x', y = 'y_strip',
        jitter = False, legend = False, palette = ['#00FF00'], ax = ax
    )

plt.show()

The new points are in the correct location, however the figure is rescaled. How do I keep the original scaling from the first plotting? Rescaled

1

There are 1 best solutions below

0
On

One option is to set_ylim to their original values:

for col, ax in g.axes_dict.items():
    ylim = ax.get_ylim()
    sns.stripplot(
        data = data.loc[data.col == col],
        x = 'x', y = 'y_strip',
        jitter = False, legend = False, palette = ['#00FF00'], ax = ax
    )    
    ax.set_ylim(ylim)

Output: enter image description here


As an aside, it's better to use .map_dataframe than to use a loop.

g = sns.catplot(kind='violin', data=data, x='x', y='y_violin', col='col', hue='hue', inner='points', dodge=False)
ylim = g.axes.flat[0].get_ylim()
g.map_dataframe(sns.stripplot, x='x', y='y_strip', jitter=False, legend=False, color='#00FF00')
g.set(ylim=ylim)