I am using seaborn.violinplot() to derive the differences between two groups. Here is my code:
import seaborn
seaborn.set(style="whitegrid")
tips = seaborn.load_dataset("tips")
seaborn.violinplot(x="day", y="total_bill", hue="smoker", data=tips, palette="Set2", dodge=True)
However, I don't want the fill color in the violin, and would like to distinguish these two groups with the color of the edge, here is an example:
How can I achieve this?
You could loop through the generated violins and set their edgecolor (which normally is dark grey) to their facecolor. You can do the same with the legend.
As seaborn prefers to saturate colors that will be used for areas, you can add saturate=1
in the call to sns.violinplot
.
import matplotlib.pyplot as plt
import matplotlib
import seaborn as sns
sns.set(style="whitegrid")
tips = sns.load_dataset("tips")
ax = sns.violinplot(x="day", y="total_bill", hue="smoker", data=tips, palette="Set2", dodge=True, saturation=1)
for collection in ax.collections:
if isinstance(collection, matplotlib.collections.PolyCollection):
collection.set_edgecolor(collection.get_facecolor())
collection.set_facecolor('none')
for h in ax.legend_.legendHandles:
if isinstance(h, matplotlib.patches.Rectangle):
h.set_edgecolor(h.get_facecolor())
h.set_facecolor('none')
h.set_linewidth(1.5)
plt.show()
The following code supposes the inner
option isn't changed from its default 'box'
. It is tested with the current seaborn version (0.12.2). The inner box is represented by two line elements: a long thin line indicating the position of the boxplot whisker, and a thicker, shorter line indicating the quartiles. In addition, there is a white point to indicate the median (represented by a PathCollection
).
import matplotlib.pyplot as plt
import matplotlib
import seaborn as sns
sns.set(style="whitegrid")
tips = sns.load_dataset("tips")
ax = sns.violinplot(x="sex", y="tip", hue="day", data=tips, palette="bright", dodge=True, saturation=1)
colors = []
for collection in ax.collections:
if isinstance(collection, matplotlib.collections.PolyCollection):
colors.append(collection.get_facecolor())
collection.set_edgecolor(colors[-1])
collection.set_facecolor('none')
if len(ax.lines) == 2 * len(colors): # suppose inner=='box'
for lin1, lin2, color in zip(ax.lines[::2], ax.lines[1::2], colors):
lin1.set_color(color)
lin2.set_color(color)
for h in ax.legend_.legendHandles:
if isinstance(h, matplotlib.patches.Rectangle):
h.set_edgecolor(h.get_facecolor())
h.set_facecolor('none')
h.set_linewidth(1.5)
plt.show()