Search code examples
pythonseabornboxplotviolin-plot

Showing both boxplots when using split in seaborn violinplots


I would like to make split violin plots which also show the boxplots for both datasets, like in the figure of the question Seaborn: How to apply custom color to each seaborn violinplot? , problem is that when using split seaborn shows only one of them (and it's not even clear to me to which dataset it refers to) as you can see in the answer, is there a way to overcome this or should I use a different package?


Solution

  • Here is an example with an artificial dataset to show how the default inner='box' shows a simple boxplot-like box for the combined dataset.

    The second plot shows how inner='quartile' looks like.

    The rightmost plot shows an approach to explicitly draw separate boxplots (using width= to place them close to the center).

    from matplotlib import pyplot as plt
    import seaborn as sns
    import pandas as pd
    import numpy as np
    
    data = pd.DataFrame({'Value': (np.random.randn(4, 100).cumsum(axis=0) + np.array([[15], [5], [12], [7]])).ravel(),
                         'Set': np.repeat(['A', 'B', 'A', 'B'], 100),
                         'x': np.repeat([1, 2], 200)})
    fig, (ax1, ax2, ax3) = plt.subplots(ncols=3, figsize=(15, 4))
    
    palette = ['paleturquoise', 'yellow']
    sns.violinplot(data=data, x='x', y='Value', hue='Set', split=True, inner='box', palette=palette, ax=ax1)
    ax1.set_title('Default, inner="box"')
    
    sns.violinplot(data=data, x='x', y='Value', hue='Set', split=True, inner='quartiles', palette=palette, ax=ax2)
    ax2.set_title('Using inner="quartiles"')
    
    sns.violinplot(data=data, x='x', y='Value', hue='Set', split=True, inner=None, palette=palette, ax=ax3)
    sns.boxplot(data=data, x='x', y='Value', hue='Set', color='white', width=0.3, boxprops={'zorder': 2}, ax=ax3)
    ax3.set_title('Explicitely drawing boxplots')
    handles, labels = ax3.get_legend_handles_labels()
    ax3.legend(handles[:2], labels[:2], title='Set')
    plt.tight_layout()
    plt.show()
    

    sns.violinplot, split with separate boxplots