Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can box plot be overlaid on top of swarm plot in Seaborn?

I am trying to plot swarm plots and box plots together using matplotlib and Seaborn. I found how to plot them together but the box plot appears underneath the swarm plot. The problem with this is that the swarm plot points drown out the box plot and the box plot is lost. I thought that by switching the order of the functions called, to have the box plot called first rather than second as in the link below, would overlay the box plot on top but it does not.

Is it possible to overlay the box plot on top of the swarm plot points? If not, is it possible to create lines indicating where the quartiles are?

Code:

swarm_name = "Swarm_Plot_01"
#
sns.set_style("whitegrid")
ax = sns.boxplot(   data = [df.Rate_VL1R, df.Rate_V12R, df.Rate_V23R, df.Rate_VM3R ],
   showcaps=False,boxprops={'facecolor':'None'},
   showfliers=False,whiskerprops={'linewidth':0})
ax = sns.swarmplot( data = [df.Rate_VL1R, df.Rate_V12R, df.Rate_V23R, df.Rate_VM3R ] )
plt.show()
fig = ax.get_figure()
fig.savefig(swarm_name)
plt.figure()

This question is related to, but not exactly the same, as How to create a swarm plot with matplotlib because I am looking to change the style, not just put the two together.

Swarm plot with box plot

like image 390
adin Avatar asked Jun 18 '17 13:06

adin


People also ask

How do you plot multiple box plots in Seaborn?

Seaborn Box Plots with Multiple Columns You can plot multiple box plots depending on the number of unique values in the categorical column for which you want to draw your box plot. The categorical column name is passed to the x variable while the numeric column name should be passed to the y variable.

What is the difference between Swarmplot and Stripplot?

Strip and swarm plots The main difference is that in a swarm plot, the data points don't overlap and are adjusted along the categorical axis. On the other hand, the issue of point overlapping in a strip plot can be partially fixed by setting the alpha parameter that regulates point transparency.

Is Seaborn built on top of Matplotlib?

Seaborn is a library for making statistical graphics in Python. It builds on top of matplotlib and integrates closely with pandas data structures.


2 Answers

The problem is that the boxplot consists of many different artists and because of the seaborn wrapping mechanism we cannot simply set the zorder of the complete boxplot to some higher number.

A first naive attempt would be to set the zorder of the swarmplot to zero. While this puts the swarmplot points behind the boxplot it also puts them behind the grid lines. This solution is thus only optimal, if no gridlines are used.

import seaborn as sns
import matplotlib.pyplot as plt
tips = sns.load_dataset("tips")

# plot swarmplot
ax = sns.swarmplot(x="day", y="total_bill", data=tips, zorder=0)
# plot boxplot
sns.boxplot(x="day", y="total_bill", data=tips, 
                 showcaps=False,boxprops={'facecolor':'None'},
                 showfliers=False,whiskerprops={'linewidth':0}, ax=ax)

plt.show()

enter image description here

If gridlines are desired, we might set the zorder of the swarmplot to 1, such that it appears above the gridlines, and set the zorder of the boxplot to a high number. As mentionned above, this requires setting the zorder property to each of it's elements as zorder=10 in the boxplot call does not affect all the artists. Instead we need to use the boxprops, whiskerprops arguments to set the zorder properity for those as well.

import seaborn as sns
import matplotlib.pyplot as plt
tips = sns.load_dataset("tips")

# plot swarmplot
ax = sns.swarmplot(x="day", y="total_bill", data=tips, zorder=1)
# plot boxplot
sns.boxplot(x="day", y="total_bill", data=tips, 
                 showcaps=False,boxprops={'facecolor':'None', "zorder":10},
                 showfliers=False,whiskerprops={'linewidth':0, "zorder":10},
                 ax=ax, zorder=10)

plt.show()

enter image description here

A final solution, which can be applied in general cases where no access at all is given to the artist properties is to loop through the axes artists and set zorder for them depending on whether they belong to the one or the other plot.

import seaborn as sns
import matplotlib.pyplot as plt
tips = sns.load_dataset("tips")

# plot swarmplot
ax = sns.swarmplot(x="day", y="total_bill", data=tips)
#get all children of axes
children1 = ax.get_children()
# plot boxplot
sns.boxplot(x="day", y="total_bill", data=tips, 
                 showcaps=False,boxprops={'facecolor':'None'},
                 showfliers=False,whiskerprops={'linewidth':0}, ax=ax)
# again, get all children of axes.
children2 = ax.get_children()
# now those children which are in children2 but not in children1
# must be part of the boxplot. Set zorder high for those.
for child in children2:
    if not child in children1:
        child.set_zorder(10)

plt.show()

enter image description here

like image 183
ImportanceOfBeingErnest Avatar answered Oct 19 '22 22:10

ImportanceOfBeingErnest


You need to change the zorder on the swarmplot:

import seaborn.apionly as sns 
tips = sns.load_dataset("tips")
sns.boxplot("day", "tip", data=tips, boxprops={'facecolor':'None'})
sns.swarmplot("day", "tip", data=tips, zorder=.5)

enter image description here

like image 38
mwaskom Avatar answered Oct 20 '22 00:10

mwaskom