2

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?

Trenton McKinney
  • 56,955
  • 33
  • 144
  • 158
alextc
  • 3,206
  • 10
  • 63
  • 107

1 Answers1

6
  • 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

Trenton McKinney
  • 56,955
  • 33
  • 144
  • 158