How can I plot different types of seaborn plots on different x ticks?

Question:

I want to have multiple types of seaborn plots using the same y axis but with different x coordinates (see image below).

I’ve tried doing this multiple different ways with specifying the X-axis coordinates differently but can’t seem to get it to work.

Here is an example of almost working code

x=[1,2,3,3,3,4,4,5,5,6] # first violin
y=[4,4,5,5,5,5,6] # second violin 
z=[5,5,6] # swarmplot over second violin


for data,label in [(x,'x'),(y,'y'),(z,'z')]:
    for i in data:
        c2v['value'].append(i)
        c2v['key'].append(label)
    

data=pd.DataFrame(c2v)
data.head()

print(data.loc[data.key=='z'])
fig,ax=plt.subplots(1,figsize=(5,5),dpi=200)
ax = sns.violinplot(data=data.loc[data.key.isin(['x','y'])], x='key', y='value',palette=['honeydew','lightgreen'])
sns.swarmplot(x=['swarmplot']*len(data), y=data['value'], order=ax.get_xticklabels() + ['swarmplot'], ax=ax)               #.loc[data.key=='z',:]
ax.set_xlabel('')

It produces the following image:

enter image description here

However, it is plotting all values associated with x/y/z instead of just z. When I slice the dataframe to only ‘z’ in the swarmplot as below, I get an error:

sns.swarmplot(x=['swarmplot']*len(data), y=data.loc[data.key=='z',:]['value'], order=ax.get_xticklabels() + ['swarmplot'], ax=ax)               
KeyError: 'swarmplot'

Any suggestions?

Asked By: Joseph Solvason

||

Answers:

To draw a second plot onto the same x-axis, you can use order= giving a list of existing tick labels, appending the new labels.

Here is an example:

import seaborn as sns

tips = sns.load_dataset('tips')
ax = sns.swarmplot(data=tips, x='day', y='total_bill')
sns.violinplot(x=['violin']*len(tips), y=tips['total_bill'], order=ax.get_xticklabels() + ['violin'], ax=ax)
ax.set_xlabel('')

combining sns.swarmplot's with an extra sns.violinplot

The problem with the code in the new question, is that the x= and y= of the swarmplot need the same number of elements. It also seems the swarmplot resets the y limits, so I added some code to readjust those:

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

x = [1, 2, 3, 3, 3, 4, 4, 5, 5, 6]  # first violin
y = [4, 4, 5, 5, 5, 5, 6]  # second violin
z = [5, 5, 6]  # swarmplot over second violin

data = pd.DataFrame({'value': np.concatenate([x, y, z]),
                     'key': ['x'] * len(x) + ['y'] * len(y) + ['z'] * len(z)})
fig, ax = plt.subplots(1, figsize=(5, 5))
ax = sns.violinplot(data=data.loc[data.key.isin(['x', 'y'])], x='key', y='value', palette=['honeydew', 'lightgreen'])
ymin1, ymax1 = ax.get_ylim()
swarm_data = data.loc[data.key == 'z', :]['value']
sns.swarmplot(x=['swarmplot'] * len(swarm_data), y=swarm_data, order=ax.get_xticklabels() + ['swarmplot'], ax=ax)
ymin2, ymax2 = ax.get_ylim()
ax.set_ylim(min(ymin1, ymin2), max(ymax1, ymax2))
ax.set_xlabel('')
ax.set_xticks(np.arange(3))
ax.set_xticklabels(['x', 'y', 'swarmplot'])
plt.show()

two violinplots and a swarmplot

You can simplify things by directly using the data without creating a dataframe:

x = [1, 2, 3, 3, 3, 4, 4, 5, 5, 6]  # first violin
y = [4, 4, 5, 5, 5, 5, 6]  # second violin
z = [5, 5, 6]  # swarmplot over second violin

fig, ax = plt.subplots(1, figsize=(5, 5))
ax = sns.violinplot(x=['x']*len(x) + ['y']*len(y), y=x + y, palette=['honeydew', 'lightgreen'])
ymin1, ymax1 = ax.get_ylim()
sns.swarmplot(x=['swarmplot'] * len(z), y=z, order=ax.get_xticklabels() + ['swarmplot'], ax=ax)
ymin2, ymax2 = ax.get_ylim()
ax.set_ylim(min(ymin1, ymin2), max(ymax1, ymax2))
ax.set_xticks(np.arange(3))
ax.set_xticklabels(['x', 'y', 'swarmplot'])
plt.show()
Answered By: JohanC
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.