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

一曲冷凌霜 提交于 2019-12-05 06:08:30

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()

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()

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()

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)

The last generic solution of ImportanceOfBeingErnest almost worked for me (Python 3.5.4) except that medians were not visible. Apparently, zorder of colored boxplots bodies hided the medians. Solution for me was to apply lower zorder to patches.

from matplotlib.patches import PathPatch

children2 = axarr[j].get_children()
for child in children2:
    if not child in children1:
        if isinstance(child, PathPatch):
            child.set_zorder(10)
        else:
            child.set_zorder(11)
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!