Pandas Box Plots: DataFrame.plot.box() and boxplot() Summaries

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.

Understanding the Five-Number Summary & Outliers 🔝

A box plot (or box-and-whisker plot) provides a compact visual representation of continuous data dispersion:

  • Median (Q2 / 50th Percentile): The central line inside the rectangular box.
  • First Quartile (Q1 / 25th Percentile): The lower boundary of the box.
  • Third Quartile (Q3 / 75th Percentile): The upper boundary of the box.
  • Interquartile Range (IQR): The height of the box (IQR = Q3 - Q1), capturing the central 50% of values.
  • Whiskers: Extend to the minimum and maximum data values within 1.5 × IQR from the quartiles ([Q1 - 1.5×IQR, Q3 + 1.5×IQR]).
  • Outliers (Fliers): Individual points plotted beyond the whisker boundaries.

Create a basic box plot with df.boxplot() 🔝

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:

DataFrame box plot displaying score dispersion across Math and English subjects
Basic box plot generated from test scores with df.boxplot()
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

Select specific numeric columns 🔝

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)

Grouped box plots with the by parameter 🔝

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()

Customise gridlines, dimensions, and tick rotation 🔝

Fine-tune readability by controlling background gridlines and label orientations:

Box plot with grid=True
grid=True (Default)
Box plot with grid=False
grid=False (Clean background)

When category labels are long, rotate them using rot to prevent overlapping text:

Box plot with rot=45 degree angle
rot=45 (Angled labels)
Box plot with rot=180 degree angle
rot=180 (Vertical inverted)
# Combine grid, label rotation, and font scaling
df.boxplot(grid=False, rot=45, fontsize=12, figsize=(6, 3.5))

Horizontal box plots with vert=False 🔝

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()

Style boxes, medians, and flier symbols 🔝

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()

Save box plots to file using savefig() 🔝

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!")

Practical workflow: departmental salary distribution & outlier audit 🔝

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

Exercise: student exam score spread analysis 🔝

Given the following test scores across 3 examination subjects, perform these tasks:

  1. Create a DataFrame containing scores for Physics, Chemistry, and Biology.
  2. Calculate the Interquartile Range (IQR) for Physics.
  3. Generate a box plot of all three subjects with horizontal whiskers (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]
}

Exercise solution 🔝

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

Practice in Google Colab 🔝

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.




Subscribe to our YouTube Channel here



plus2net.com







Python Video Tutorials
Python SQLite Video Tutorials
Python MySQL Video Tutorials
Python Tkinter Video Tutorials
✖
We use cookies to improve your browsing experience. . Learn more
HTML MySQL PHP JavaScript ASP Photoshop Articles Contact us
© 2000-2026 plus2net.com All rights reserved worldwide Privacy Policy Disclaimer