HOWTO · Seaborn
How to Create a Seaborn Box Plot in Python
Create Seaborn box plots in Python, compare categories, show individual observations, and customize the plot.
On this page
Use seaborn.boxplot() to summarize a numeric distribution or compare values across categories. Map your data columns explicitly so Seaborn knows which variable belongs on each axis. A box plot shows the median and interquartile range (IQR); with the default whisker rule, whiskers reach the most extreme observations within 1.5 IQR of the box, and more distant observations appear as individual points.
Every example in this article uses the same parts: the box covers the middle half of the data, the line inside it is the median, the whiskers mark the range under the selected rule, and any points beyond the whiskers are plotted individually.
Create a Box Plot for One Distribution
Put the measurements in a DataFrame column and map that column to y. This makes the data role clear and gives the plot a useful axis label. The example below uses fixed values, so the same input is used each time you run it.
import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns
data = pd.DataFrame({"Score": [12, 14, 15, 16, 18, 19, 21, 24]})
ax = sns.boxplot(data=data, y="Score")
ax.set_title("Score distribution")
plt.show()
The line inside the box marks the median. The box spans the first through third quartiles, so its height represents the middle half of the observations. A longer box indicates greater spread in that central portion of the data. The whiskers show the range under the selected whisker rule; they do not necessarily reach the minimum and maximum values.
Compare Distributions Across Categories
Map a category to x and the numeric measurement to y to place a separate box at each category. In this dataset, each box summarizes Price for one Quantity level. Adding hue="Product" divides each category into product groups, which helps compare products at the same quantity.
import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns
data = pd.DataFrame(
{
"Quantity": [5, 6, 7, 8, 5, 6, 7, 8, 5, 6, 7, 8, 5, 6, 7, 8],
"Price": [9, 10, 15, 16, 13, 14, 15, 18, 11, 12, 14, 15, 16, 17, 18, 19],
"Product": ["A", "A", "A", "A", "B", "B", "B", "B"] * 2,
}
)
ax = sns.boxplot(data=data, x="Quantity", y="Price", hue="Product")
ax.set_title("Price by quantity and product")
plt.show()
Use hue when the extra grouping answers a comparison question. If there are many groups, the boxes can become crowded; simplify the categories or create separate plots so the distributions remain readable.
Show Individual Observations with a Strip Plot
A box plot compresses the data into summary statistics. Overlay seaborn.stripplot() when readers also need to see each observation. Reuse the same axis and mappings for both layers, and add a small amount of horizontal jitter so points with similar values do not completely overlap.
import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns
data = pd.DataFrame({"Score": [12, 14, 15, 16, 18, 19, 21, 24]})
ax = sns.boxplot(data=data, y="Score", color="lightgray")
sns.stripplot(data=data, y="Score", color="darkred", jitter=0.15, ax=ax)
ax.set_title("Scores with individual observations")
plt.show()
The box remains the summary, while each marker represents one row in the data. On a larger dataset, points may overlap; adjust the marker size or transparency to keep dense regions legible.
Customize the Box Plot
Use Matplotlib axis-limit methods to focus on a relevant value range, linewidth to change box and whisker border thickness, and palette to assign colors to categories. The orient parameter controls direction; for example, orient="h" requests a horizontal plot when the mappings are compatible. Axis limits only change the displayed view, so choose them carefully and keep the scale clear to avoid hiding relevant observations.
import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns
data = pd.DataFrame(
{
"Quantity": [5, 6, 7, 8, 5, 6, 7, 8, 5, 6, 7, 8, 5, 6, 7, 8],
"Price": [9, 10, 15, 16, 13, 14, 15, 18, 11, 12, 14, 15, 16, 17, 18, 19],
"Product": ["A", "A", "A", "A", "B", "B", "B", "B"] * 2,
}
)
ax = sns.boxplot(
data=data,
x="Quantity",
y="Price",
hue="Product",
linewidth=2.5,
palette="Set2",
)
ax.set_ylim(8, 20)
ax.set_title("Customized price comparison")
plt.show()
The palette colors correspond to the hue groups. To use horizontal boxes, swap the category and measurement mappings and set orient="h"; axis limits should then be applied with set_xlim() rather than set_ylim().
Create a Box Plot with catplot()
Use catplot() with kind="box" for the figure-level interface. It accepts the same explicit data mappings and can create separate panels with col or row when another variable should split the comparison. For a single plot, seaborn.boxplot() is the axes-level option; catplot() is convenient when the figure needs facets.
import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns
data = pd.DataFrame(
{
"Quantity": [5, 6, 7, 8, 5, 6, 7, 8, 5, 6, 7, 8, 5, 6, 7, 8],
"Price": [9, 10, 15, 16, 13, 14, 15, 18, 11, 12, 14, 15, 16, 17, 18, 19],
}
)
grid = sns.catplot(data=data, x="Quantity", y="Price", kind="box")
grid.set_axis_labels("Quantity", "Price")
grid.fig.suptitle("Price by quantity")
plt.show()
Because catplot() builds the whole figure, it returns a grid object rather than a single axes; set labels and titles on the grid, as in the example, instead of calling ax.set_title().
Handle a Missing Column Error and Set the Whisker Range
Because every mapping names a DataFrame column, a misspelled name fails before anything is drawn. This call asks for a column Scroe that the data does not contain:
import pandas as pd
import seaborn as sns
data = pd.DataFrame({"Score": [12, 14, 15, 16, 18, 19, 21, 24]})
ax = sns.boxplot(data=data, y="Scroe")
The call ends with this error:
ValueError: Could not interpret value `Scroe` for `y`. An entry with this name does not appear in `data`.
Fix the name to match the column exactly — here, y="Score" — and the same call draws the plot. When the correct spelling is not obvious, print data.columns and copy the name from there; the check applies to x, y, and hue alike.
The whiskers are the other boundary readers meet. Add one far value, 60, to the scores: the quartiles barely move (first quartile 15, median 18, third quartile 21), and with the default whis=1.5 the upper whisker stops at 24 while 60 is drawn as a lone point beyond it. Passing whis as a pair of percentiles stretches the whiskers to those percentiles of the data instead:
import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns
scores = pd.DataFrame({"Score": [12, 14, 15, 16, 18, 19, 21, 24, 60]})
ax = sns.boxplot(data=scores, y="Score", whis=(0, 100))
plt.show()
With whis=(0, 100), the whiskers reach the minimum 12 and the maximum 60, and no points remain outside them. Prefer the default unless the full range is the message: stretched whiskers hide how unusual the extreme value is. Note also that an empty column does not raise an error — Seaborn returns an empty set of axes — so check the row count before plotting when the data comes from a pipeline.