Use DataFrame.plot.box() or DataFrame.boxplot() to display the five-number summary (minimum, first quartile Q1, median Q2, third quartile Q3, and maximum) along with statistical outliers. Box plots are essential for comparing numeric distributions across groups, detecting skewness, and identifying extreme data points without assuming a normal distribution.
A box plot (or box-and-whisker plot) provides a compact visual representation of continuous data dispersion:
IQR = Q3 - Q1), capturing the central 50% of values.[Q1 - 1.5×IQR, Q3 + 1.5×IQR]).Pandas provides two convenient methods for creating box plots: df.boxplot() (the dedicated wrapper) and df.plot.box() (the standard Plot accessor). Let us inspect subject scores across multiple students:
import pandas as pd
import matplotlib.pyplot as plt
my_dict = {
"MATH": [30, 33, 32, 32, 31, 34, 32],
"ENG": [32, 31, 35, 34, 35, 34, 32]
}
df = pd.DataFrame(data=my_dict)
print(df)
# Plot summary box plot with default grid
df.boxplot(figsize=(5, 3.5), grid=True)
plt.title("Student Marks Distribution")
plt.tight_layout()
plt.show()
Expected console output:
MATH ENG
0 30 32
1 33 31
2 32 35
3 32 34
4 31 35
5 34 34
6 32 32
When working with large tables containing dozens of metrics, restrict the chart to specific columns using the column parameter:
# Isolate a single series
df.boxplot(column="MATH", figsize=(4, 3.5))
# Or pass a list of specific columns
df.boxplot(column=["MATH", "ENG"], figsize=(6, 3.5), grid=True)
To compare numeric distributions partitioned by a categorical variable (such as branch, department, or gender), supply the category column to by:
data = {
"CLASS": ["A", "A", "A", "B", "B", "B", "B"],
"SCORE": [75, 82, 88, 64, 70, 72, 95]
}
df_class = pd.DataFrame(data)
# Generate separate side-by-side boxes for Class A vs Class B
df_class.boxplot(column="SCORE", by="CLASS", figsize=(6, 4))
plt.suptitle("") # Remove default automated subtitle
plt.title("Test Score Dispersion by Classroom")
plt.show()
Fine-tune readability by controlling background gridlines and label orientations:
When category labels are long, rotate them using rot to prevent overlapping text:
# Combine grid, label rotation, and font scaling
df.boxplot(grid=False, rot=45, fontsize=12, figsize=(6, 3.5))
By default, box plots display vertically. Set vert=False to orient whiskers horizontally along the X-axis. This format is ideal for reading long category names on the Y-axis:
df.plot.box(vert=False, figsize=(6, 3), title="Horizontal Score Distribution")
plt.xlabel("Scores")
plt.tight_layout()
plt.show()
You can customize the styling of boxes, whiskers, medians, and outlier points (fliers) by passing color dictionaries or enabling patch_artist=True:
color_dict = {
"boxes": "DarkGreen",
"whiskers": "DarkOrange",
"medians": "DarkRed",
"caps": "Gray"
}
# Apply custom color dictionary with filled patch artist
df.plot.box(color=color_dict, patch_artist=True, figsize=(6, 3.5))
plt.title("Custom Styled Box Plot")
plt.show()
Export your finalized box plot to PNG, PDF, or SVG for reporting workflows:
ax = df.boxplot(figsize=(6, 4))
plt.title("Subject Comparison Report")
plt.tight_layout()
plt.savefig("boxplot_report.png", dpi=300)
plt.close()
print("Exported boxplot_report.png successfully!")
In compensation analytics, HR teams compare salary bands across departments to detect inequities and identify outliers. In the example below, we calculate quartile metrics and plot departmental distributions:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
np.random.seed(42)
departments = ["Engineering"] * 25 + ["Marketing"] * 25 + ["Finance"] * 25
salaries = (
list(np.random.normal(95000, 12000, 25)) +
list(np.random.normal(72000, 8000, 25)) +
list(np.random.normal(84000, 10000, 25))
}
salaries[0] = 145000
df_salaries = pd.DataFrame({
"Department": departments,
"Salary": np.round(salaries, -2)
})
# Summary statistics per department
summary = df_salaries.groupby("Department")["Salary"].describe()
print(summary[["25%", "50%", "75%", "max"]])
# Plot comparison box plot
plt.figure(figsize=(7, 4))
df_salaries.boxplot(column="Salary", by="Department", grid=True, rot=15)
plt.suptitle("")
plt.title("Salary Distribution by Department (Auditing Outliers)")
plt.ylabel("Annual Salary (USD)")
plt.tight_layout()
plt.show()
Expected console output:
25% 50% 75% max
Department
Engineering 88300.0 92200.0 101500.0 145000.0
Finance 79200.0 87200.0 93300.0 99600.0
Marketing 63500.0 69700.0 73700.0 86800.0
Given the following test scores across 3 examination subjects, perform these tasks:
Physics, Chemistry, and Biology.Physics.vert=False), a title of "Science Exam Spread", and grid=True.exam_data = {
"Physics": [58, 64, 72, 75, 78, 82, 85, 98],
"Chemistry": [62, 68, 70, 74, 76, 80, 84, 88],
"Biology": [70, 75, 79, 81, 84, 86, 89, 92]
}
import pandas as pd
import matplotlib.pyplot as plt
exam_data = {
"Physics": [58, 64, 72, 75, 78, 82, 85, 98],
"Chemistry": [62, 68, 70, 74, 76, 80, 84, 88],
"Biology": [70, 75, 79, 81, 84, 86, 89, 92]
}
df_exams = pd.DataFrame(exam_data)
# Calculate Q1, Q3, and IQR for Physics
q1_phys = df_exams["Physics"].quantile(0.25)
q3_phys = df_exams["Physics"].quantile(0.75)
iqr_phys = q3_phys - q1_phys
print(f"Physics Q1: {q1_phys:.1f}")
print(f"Physics Q3: {q3_phys:.1f}")
print(f"Physics IQR: {iqr_phys:.1f}")
# Validation assertions
assert q1_phys == 70.0
assert q3_phys == 82.75
assert iqr_phys == 12.75
# Horizontal box plot
df_exams.plot.box(vert=False, grid=True, figsize=(6.5, 3.5), title="Science Exam Spread")
plt.xlabel("Score out of 100")
plt.tight_layout()
plt.show()
Expected console output:
Physics Q1: 70.0
Physics Q3: 82.8
Physics IQR: 12.8
Experiment with box plot options, quartile calculations, and grouped categorizations in our interactive Google Colab practice notebook:
Open in Google Colab View on GitHub
Run the box plot examples interactively, test quartile calculations, inspect outlier fliers, and verify the practice exercise directly in Google Colab. All sample datasets are embedded directly in the notebook.
Reference: Pandas DataFrame.boxplot official documentation.
Author & Instructor at plus2net
I write and maintain practical tutorials on Python, PHP, SQL, JavaScript, HTML, jQuery, and web development at plus2net. The tutorials focus on clear explanations, working examples, and code that readers can test and adapt while learning.