Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

seaborn boxplot and stripplot points aren't aligned over the x-axis by hue

I have the following code to draw a boxplot and overlay all data points on the bars.

import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
import numpy.random as rnd

f = plt.figure(figsize=[18,12])
ax = f.add_subplot(111)
sns.boxplot(x='month', y='ffdi', hue='scenario', data=df_diff_concat, ax=ax)
sns.stripplot(x="month", y="ffdi",hue='scenario', data=df_diff_concat, ax=ax)

enter image description here

The data points are not vertically aligned with the middleline of the bar they belong to.

How can this be fixed?

like image 967
alextc Avatar asked Oct 18 '25 10:10

alextc


1 Answers

  • Use dodge=True in seaborn.stripplot, otherwise the values are plotted as a single group centered over the x-tick
  • See How to overlay data points on a barplot figure-level plot, where the kind='bar' can be replaced with kind='box'
  • Tested in python 3.8.11, matplotlib 3.4.3, seaborn 0.11.2
import seaborn as sns

# load the dataframe
tips = sns.load_dataset('tips')

ax = sns.boxplot(x="day", y="total_bill", hue="smoker", data=tips, palette="GnBu")

# add stripplot with dodge=True
sns.stripplot(x="day", y="total_bill", hue="smoker", data=tips, palette="GnBu", dodge=True, ax=ax, ec='k', linewidth=1)

# remove extra legend handles
handles, labels = ax.get_legend_handles_labels()
ax.legend(handles[:2], labels[:2], title='Smoker', bbox_to_anchor=(1, 1.02), loc='upper left')

enter image description here

  • To get the points all in a single line, also set jitter=False, but all data points won't show when there's overlap.
ax = sns.boxplot(x="day", y="total_bill", hue="smoker", data=tips, palette="GnBu")

# add stripplot with dodge=True
sns.stripplot(x="day", y="total_bill", hue="smoker", data=tips, palette="GnBu",
              dodge=True, ax=ax, ec='k', linewidth=1, jitter=False)

# remove extra legend handles
handles, labels = ax.get_legend_handles_labels()
ax.legend(handles[:2], labels[:2], title='Smoker', bbox_to_anchor=(1, 1.02), loc='upper left')

enter image description here

  • Use seaborn.swarmplot, which is similar to stripplot(), but the points are adjusted (only along the categorical axis) so that they don’t overlap.
ax = sns.boxplot(x="day", y="total_bill", hue="smoker", data=tips, palette="GnBu")

# add stripplot with dodge=True
sns.swarmplot(x="day", y="total_bill", hue="smoker", data=tips, palette="GnBu",
              dodge=True, ax=ax, ec='k', linewidth=1, size=3)

# remove extra legend handles
handles, labels = ax.get_legend_handles_labels()
ax.legend(handles[:2], labels[:2], title='Smoker', bbox_to_anchor=(1, 1.02), loc='upper left')

enter image description here

like image 155
Trenton McKinney Avatar answered Oct 21 '25 19:10

Trenton McKinney