MonsieurWave
MonsieurWave

Reputation: 339

How to display boxplot in front of violinplot in seaborn - seaborn zorder?

To customize the styles of the boxplot displayed inside a violinplot, on could try to plot a boxplot in front of a violinplot. However this does not seem to work as it is always displayed behind the violinplot when using seaborn.

When using seaborn + matplotlib this works (but only for a single category):

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

df=pd.DataFrame(np.random.rand(10,2)).melt(var_name='group')

fig, axes = plt.subplots()

# Seaborn violin plot
sns.violinplot(y=df[df['group']==0]['value'], color="#af52f4", inner=None, linewidth=0, saturation=0.5)

# Normal boxplot has full range, same in Seaborn boxplot
axes.boxplot(df[df['group']==0]['value'], whis='range', positions=np.array([0]),
            showcaps=False,widths=0.06, patch_artist=True,
            boxprops=dict(color="indigo", facecolor="indigo"),
            whiskerprops=dict(color="indigo", linewidth=2),
            medianprops=dict(color="w", linewidth=2 ))

axes.set_xlim(-1,1)

plt.show()

correctly placed boxplot

However when using only seaborn to be able to plot across multiple categories, ordering is always wrong:

sns.violinplot(data=df, x='group', y='value', color="#af52f4", inner=None, linewidth=0, saturation=0.5)
sns.boxplot(data=df, x='group', y='value', saturation=0.5)


plt.show()

incorrectly placed boxplot

Even when trying to fix this with zorder this does not work.

Upvotes: 4

Views: 5932

Answers (1)

JohanC
JohanC

Reputation: 80449

The zorder parameter of sns.boxplot only affects the lines of the boxplot, but not the rectangular box.

One possibility is to access these boxes afterwards; they form the list of artists in ax.artists. Setting their zorder=2 will put them in front of the violins while still being behind the other boxplot lines.

In the comments, @mwaskom, noted a better way. sns.boxplot delegates all parameters it doesn't recognize via **kwargs to ax.boxplot. One of these is boxprops with the properties of the box rectangle. So, boxprops={'zorder': 2} would change the zorder of only the box.

Here is an example:

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

df = pd.DataFrame(np.random.rand(10, 2)).melt(var_name='group')
ax = sns.violinplot(data=df, x='group', y='value', color="#af52f4", inner=None, linewidth=0, saturation=0.5)
sns.boxplot(data=df, x='group', y='value', saturation=0.5, width=0.4,
            palette='rocket', boxprops={'zorder': 2}, ax=ax)
plt.show()

sns.boxplot in front of sns.violinplot

Here is another example, using the tips dataset:

tips = sns.load_dataset('tips')
ax = sns.violinplot(data=tips, x='day', y='total_bill', palette='turbo',
                    inner=None, linewidth=0, saturation=0.4)
sns.boxplot(x='day', y='total_bill', data=tips, palette='turbo', width=0.3,
            boxprops={'zorder': 2}, ax=ax)

seaborn violinplot with boxplot for tips dataset

Upvotes: 8

Related Questions