How to plot a box plot without hiding observations in Seaborn (with Code)
The Short Answer (TL;DR)
Draw a Seaborn boxplot and overlay a stripplot using the same data and category order. Set showfliers=False on the boxplot so unusual observations appear once in the point layer instead of being drawn twice.
import numpy as np, pandas as pd, seaborn as sns
data = pd.DataFrame({"group": ["A"] * 6 + ["B"] * 6, "value": [1, 2, 2, 3, 4, 9, 2, 3, 4, 4, 5, 6]}); np.random.seed(14)
ax = sns.boxplot(data=data, x="group", y="value", order=["A", "B"], showfliers=False, color="lightgray"); sns.stripplot(data=data, x="group", y="value", order=["A", "B"], jitter=0.12, color="black", ax=ax)
Detailed Implementation
This example uses synthetic data and does not need a network connection. Install the recorded package versions in a separate Python environment before running it.
python -m pip install numpy==2.5.4 pandas==3.0.6 matplotlib==3.11.2 seaborn==0.13.2
import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
data = pd.DataFrame({
"group": ["A"] * 6 + ["B"] * 6,
"value": [1, 2, 2, 3, 4, 9, 2, 3, 4, 4, 5, 6],
})
order = ["A", "B"]
np.random.seed(14) # Reproduce the horizontal jitter, not the measurements.
fig, ax = plt.subplots(figsize=(5.5, 3.8), layout="constrained")
sns.boxplot(data=data, x="group", y="value", order=order,
showfliers=False, color="lightgray", width=0.6, ax=ax)
sns.stripplot(data=data, x="group", y="value", order=order,
jitter=0.12, color="black", size=5, ax=ax)
ax.set(xlabel="Group (six observations each)", ylabel="Synthetic measurement",
title="Box summaries with individual observations")
fig.savefig("boxplot-with-observations.png", dpi=160)
plt.show()
Two boxes summarize groups A and B, with twelve observation markers in total. The high value nine in group A is visible in the point layer, and the group A median is 2.5.
Does showfliers=False remove unusual observations?
The setting hides the boxplot layer's separate flier symbols. The stripplot still receives all twelve rows, including the value nine in group A. Do not filter the data merely because a point lies beyond a whisker.
Why must category order match?
The two calls draw into the same axes. Supplying the same order keeps the observations over their own group's box; different orders can silently place one group's points over another group's summary.
Can observations still overlap?
Horizontal jitter moves markers sideways while preserving their measured y values. It reduces overlap without guaranteeing separation, especially in large samples. State sample sizes and consider a swarm plot for small datasets when avoiding overlap matters.
Mathematical Context
The box spans the first and third sample quartiles, with a line at the median. The interquartile range is IQR = Q3 – Q1. With the default whisker rule, whiskers reach the most extreme observed values inside the 1.5 IQR fences. Group A has Q1=2 and Q3=3.75, so its upper fence is 6.375; nine is beyond that fence and remains in the point layer. A boxplot is descriptive, and its whiskers are not a confidence interval.
\[ \mathrm{IQR}=Q_3-Q_1,\qquad [Q_1-1.5\,\mathrm{IQR},\ Q_3+1.5\,\mathrm{IQR}] \]
Reproducibility
Executed with Python 3.12.14; numpy 2.5.4, pandas 3.0.6, matplotlib 3.11.2, seaborn 0.13.2. Automated checks confirm the stated output properties.
Primary documentation
Related guides
- Learn Python plotting with Matplotlib
- How to share a colorbar across subplots in Matplotlib (with Code)
- How to save a figure with a transparent background in Matplotlib (with Code)
- How to plot error bars from measured standard errors in Matplotlib (with Code)
- How to add a logarithmic axis in Matplotlib (with Code)
- How to format dates on a time-series axis in Matplotlib (with Code)
- How to plot a histogram with unequal bin widths in Matplotlib (with Code)