issues with overlaying boxplot with stripplot

Viewed 135

i'm overlaying a boxplot with a stripplot using the following code:

# create a color palette
palette = ['tab:blue', 'tab:orange', 'tab:red',]

# plot the data
plt.figure(figsize = (18,8))
sns.stripplot(data = int_genes_melt, y = 'value', x = 'Genes', color = 'black')
sns.boxplot(data = int_genes_melt, y = 'value', x = 'Genes', hue = 'pulldown', hue_order= ['BT474', 'both', 'SKBR3'], palette = palette)
plt.ylabel('relative protein abundance to control')
plt.xticks(rotation=40)
sns.despine()

The output looks like this:

enter image description here

As you can see some datapoints from the stripplot overlap perfectly with the boxplot (boxplot orange). However, first red boxplot on the left doesn't seem to overlap with the stripplot as nicely. Any suggestions why this is happening?

2 Answers

Within the seaborn.stripplot call, you could additionally set: dodge=True + Jitter=True

For example:

import seaborn as sns
import matplotlib.pyplot as plt


tips = sns.load_dataset('tips')

ax = sns.boxplot(x="day", y="total_bill", hue="smoker", data=tips)
sns.stripplot(x="day", y="total_bill", hue="smoker", data=tips, dodge=True, ax=ax, jitter=True)

plt.show()

An alternative could be presenting a swarmplot instead. For example:

ax = sns.boxplot(x="day", y="total_bill", hue="smoker", data=tips)
sns.swarmplot(x="day", y="total_bill", hue="smoker", data=tips, dodge=True, ax=ax, linewidth=1, size=3)

plt.show()

Why you get this output

This is cause by not all kind of 'Genes' in int_genes_melt have these three kind(['BT474', 'both', 'SKBR3']) of 'pulldown'.

Take the first category (The first box and the associated points on the graph) of 'Genes' as an example. There is only one red box, indicating that in the first category the 'pulldown' attributes of all datapoints' are 'SKBR3'('SKBR3' is colored as 'tab:red' according to the hue_order).

  1. The boxplot behavior. The boxes representing 'BT474' and 'both' is missing. This is because that there is no such data in the first category that have these two kind of 'pulldown'. As a result, only the last one of the three boxes belong to the first category of 'Genes' is plotted.

  2. The stripplot behavior, the points of the first category is plotted at the center, about where the second box of 'both' is located, just on the left of the box 'SKBR3'.

So you can see in the first category the points is located at the left of the box. As another example, in the fifth category, however, all data have 'both' as their 'pulldown' attribute, so the second box of the three box is plotted, just aligned with the stripplot.

You can refer to the document of boxplot, search on the page with "Draw a boxplot with nested grouping when some bins are empty", and you can find an official example illustrating this behavior of the boxplot.

How to fix it

You can add hue='pulldown' attribute and set dodge=True. In this way, the stripplot of each category will also be devided to three strips according to there pulldown attribute.

You can refer to the document of stripplot and you willl find that you can "Draw each level of the hue variable at different locations on the major categorical axis".

The following is a code example:

Without this hue= and dodge=True:

import seaborn as sns
import matplotlib.pyplot as plt
palette = ['tab:blue', 'tab:orange']
tips = sns.load_dataset("tips")
sns.stripplot(data=tips, y='total_bill', x='day', color='black')
sns.boxplot(data=tips, x="day", y="total_bill", hue="time", hue_order=['Lunch', 'Dinner'], palette=palette)
sns.despine()
plt.show()

Which gives(Notes that the boxplot and the stripplot are not aligned, the third and the fourth column are just like your situation):

enter image description here And after fixing:

import seaborn as sns
import matplotlib.pyplot as plt
palette = ['tab:blue', 'tab:orange']
tips = sns.load_dataset("tips")
sns.stripplot(data=tips, y='total_bill', x='day', hue="time", dodge=True, color='black')
sns.boxplot(data=tips, x="day", y="total_bill", hue="time", hue_order=['Lunch', 'Dinner'], palette=palette)
sns.despine()
plt.show()

Which gives: enter image description here

As for your code, I think you should use(as @Michael has pointed out):

sns.stripplot(data=int_genes_melt, y='value', x='Genes', hue='pulldown', hue_order=['BT474', 'both', 'SKBR3'],  dodge=True, color='black')

You can also turn off the legend refering to this link if you want.

Related