Plot Histograms and Box Plots

Learn to create histograms and box plots in Python for data science. This lesson covers the core concepts, step-by-step instructions, hands-on coding exercises, and troubleshooting tips.

Focus: plot histograms and box plots

Sponsored

You've been wrangling DataFrames, cleaning missing values, and computing summary stats — but numbers alone hide the story. When you call df.describe(), you get the mean and median, yet you have no idea whether the data is skewed, where the outliers lurk, or how a distribution shifts across categories. That's exactly the problem this lesson solves: plot histograms and box plots to make the invisible structure of your data visible. In this step of your Python data science journey, you'll move beyond tables and start seeing your data — turning abstract statistics into insights you can act on.

The problem this lesson solves

Raw numbers are deceptive. Consider a dataset of customer purchase amounts: the mean might be \$85, but a few whale customers spending \$2,000 can inflate that average, masking the fact that 90% of your customers spend under \$50. A simple describe() call gives you the mean, median, and percentiles, but it doesn't reveal:

  • Is the data symmetric or skewed?
  • Are there outliers that will wreck your model?
  • How does the distribution change across groups (e.g., by city or by product)?

Without visualizations, you're flying blind. Histograms show the shape of a single numeric variable's distribution, while box plots (a.k.a. box-and-whisker plots) summarize the distribution with a five-number summary and explicitly flag outliers. Together, they answer the questions that summary statistics can't — quickly, intuitively, and persuasively when you present your findings.

By the end of this lesson, you'll be able to create both chart types in Python using Matplotlib and Seaborn, interpret them to make data-driven decisions, and know when to reach for each one.

Core concept / mental model

Think of a histogram as a topographic map of your data's frequency. You split the range of values into bins (contiguous intervals) and count how many observations fall into each bin. The result is a bar chart where the height of each bar shows how dense the data is in that region. Peaks show common values; long tails show rare extremes.

A box plot is like a satellite view that condenses the distribution into five key numbers:

  • Median (Q2): the middle value
  • First quartile (Q1): 25th percentile
  • Third quartile (Q3): 75th percentile
  • Whiskers: typically extend to the most extreme data points within 1.5 × IQR of the quartiles
  • Flier points: individual points beyond the whiskers, which are potential outliers

Where the histogram shows the full shape of the distribution, the box plot gives you a compact summary — especially powerful for comparing many groups side by side.

Analogy: A histogram is a photograph; a box plot is a technical schematic. The photograph shows you every nuance; the schematic highlights the key measurements.

Terminology to remember: - Bin: the interval width in a histogram (e.g., 0–10, 10–20) - Frequency: the count of observations in each bin - IQR (Interquartile Range): Q3 − Q1, the middle 50% spread

How it works step by step

Creating a histogram or box plot in Python follows a simple, repeatable process:

  1. Prepare your data — ensure your numeric column is in a pandas Series or DataFrame and free of missing values (or at least handle them deliberately).
  2. Import the plotting librariesmatplotlib.pyplot for low-level control, seaborn for statistical convenience.
  3. Choose your plot: - Histogram: use plt.hist() or sns.histplot(). - Box plot: use plt.boxplot() or sns.boxplot().
  4. Customize — set titles, axis labels, colors, and (for histograms) bin widths.
  5. Interpret — look at the shape, central tendency, spread, and outliers, then translate that into a business or scientific insight.

For a histogram, the critical tuning knob is the bin width. Too few bins can hide the shape; too many can make it look jagged and noisy. There's no universal rule, but common strategies include:

  • Use the square-root rule: bins ≈ sqrt(n)
  • Use Sturges' rule (default in many tools): bins ≈ log2(n) + 1
  • Try 10–20 bins for a first pass, then adjust based on what reveals the story.

For a box plot, there's no bin parameter — but you must decide whether to plot one column or compare multiple groups, and whether to show outliers (showfliers=True, the default) or hide them.

Hands-on walkthrough

Let's get practical. Start by importing the tools and creating a small dataset to work with.

import pandas as pd
import matplotlib.pyplot as plt
import numpy as np

# Simulate a skewed dataset: e.g., customer spend (log-normal)
np.random.seed(42)
data = {
    'spend': np.random.lognormal(mean=3.0, sigma=0.8, size=500),
    'region': np.random.choice(['North', 'South', 'East', 'West'], size=500)
}
df = pd.DataFrame(data)
df.head()

Expected output (first few rows):

      spend region
0  17.837   East
1  31.228   West
2  30.831   North
3  12.993   South
4  27.331   East

Now create a histogram:

plt.figure(figsize=(8, 5))
plt.hist(df['spend'], bins=30, edgecolor='black', alpha=0.7, color='steelblue')
plt.title('Distribution of Customer Spend')
plt.xlabel('Spend ($)')
plt.ylabel('Frequency')
plt.grid(True, linestyle='--', alpha=0.5)
plt.show()

This plot reveals a right-skewed distribution — most customers spend a small amount, with a long tail of high spenders. That's exactly the kind of insight a summary table hides.

Now for a box plot of the same data:

plt.figure(figsize=(6, 5))
plt.boxplot(df['spend'], vert=True, patch_artist=True,
            boxprops=dict(facecolor='lightblue'),
            medianprops=dict(color='red', linewidth=2))
plt.title('Box Plot of Customer Spend')
plt.ylabel('Spend ($)')
plt.grid(True, linestyle='--', alpha=0.5)
plt.show()

The box plot clearly shows the median (red line), the interquartile range (the box), and a bunch of flier points above the upper whisker — potential outliers. But to make outliers precise, we can use Seaborn, which provides a cleaner API and built-in statistical formatting.

import seaborn as sns

plt.figure(figsize=(8, 5))
sns.histplot(df['spend'], bins=30, kde=True, color='green')
plt.title('Histogram with KDE')
plt.xlabel('Spend ($)')
plt.show()

Adding a KDE (kernel density estimate) curve overlays a smooth estimate of the distribution, making the shape even more apparent.

plt.figure(figsize=(8, 5))
sns.boxplot(x='region', y='spend', data=df, palette='Set2')
plt.title('Spend by Region')
plt.xlabel('Region')
plt.ylabel('Spend ($)')
plt.show()

Here, the box plot shines: you can compare the spread and median of spend across all four regions simultaneously, instantly spotting that some regions have wider variability and more outliers.

Pro tip: Before plotting, always check for missing values in the column you're plotting. A NaN will often just be dropped by Matplotlib, but it's better to handle it deliberately — use df.dropna(subset=['spend']) if appropriate.

Compare options / when to choose what

Situation Histogram Box plot
Show full distribution shape (skew, multimodality) ✅ Best ❌ Too compact
Compare many groups side by side ❌ Cluttered ✅ Best
Identify outliers explicitly ⚠️ Possible but not precise ✅ Clear flier points
Quick summary of median/IQR ⚠️ Indirect ✅ Direct
Presentation to non‑technical audience ✅ Intuitive ✅ Also intuitive

When to use a histogram: When you need to see the shape of a single variable — whether it's normal, skewed, bimodal, or uniform. Use it in exploratory data analysis (EDA) before modeling.

When to use a box plot: When you need to compare distributions across categories, or when you have many variables and want a compact view of each one's spread. Box plots are also excellent for highlighting outliers that might indicate data errors or genuinely extreme cases.

Variations to consider: - Grouped histograms (overlay multiple histograms with transparency) to compare distributions directly. - Violin plots (Seaborn's sns.violinplot()) combine box-like summary with a rotated KDE — nice middle ground. - Empirical CDF plots (sns.ecdfplot()) are great for showing cumulative proportions.

Troubleshooting & edge cases

1. My histogram looks like a single tall bar / too jagged. This is almost always a bin width problem. If a few bins dominate, increase the number of bins (smaller bin width) to reveal shape. If it's too jagged, decrease the number of bins (wider bins) to smooth noise.

2. The box plot shows outliers that don't make sense. First, verify your data — outliers may be typos or measurement errors. Use the whisker definition (1.5 × IQR) to sanity-check. If you want to suppress them temporarily, set showfliers=False in plt.boxplot() or sns.boxplot(showfliers=False), but never ignore them silently — investigate why they're there.

3. The x-axis labels are overlapping when comparing groups. Rotate the labels: plt.xticks(rotation=45) or plt.tight_layout() to fix layout.

4. My box plot appears empty or has no boxes. Check if your column has a constant value (all identical) or too few data points. If the IQR is zero, the box collapses to a line. Consider using a wider dataset or a different visualization.

5. Histogram bins aren't aligned with my labels. In plt.hist(), the align parameter ('left', 'mid', 'right') controls bin edge alignment. Use align='mid' for centered bars, especially when using integer bin edges.

6. KDE curve extends into negative values when data is strictly positive. The KDE doesn't respect bounds. You can clip it: sns.histplot(..., kde=True, binrange=(0, None)) or simply ignore the overshoot if it's minor.

What you learned & what's next

In this lesson, you've mastered the art of plotting histograms and box plots with Python's Matplotlib and Seaborn. You can now:

  • Create a histogram to visualize the distribution of a numeric column, adjusting bins to reveal the true shape.
  • Build a box plot to summarize spread and detect outliers at a glance.
  • Compare multiple groups side by side and choose the right plot for your analytical question.

These skills are foundational for any data science exploration — you'll use them in almost every EDA session. But they're only the beginning. In the next lesson, we'll dive into scatter plots and correlation — connecting two numeric variables to uncover relationships and trends. You'll take the same mindset of 'see before you model' and apply it to multivariate data.

Open your Jupyter notebook, grab your favorite dataset (or use the one we created), and try plotting a histogram and a box plot for every numeric column. Ask yourself: What shape does the data take? Are there outliers that need investigation? How do groups differ? The more you practice, the faster you'll spot issues and insights that numbers alone can't reveal.

Practice recap

Now it's your turn: load any dataset with numeric columns (e.g., from Seaborn's tips or iris) and create histograms for each numeric variable. Then, build box plots to compare two or more categories. For at least one histogram, experiment with different bins values and note how the story changes. Finally, identify the outliers in a box plot and decide whether they are genuine or errors — this process is exactly what you'll do in real projects.

Common mistakes

  • Using too few or too many bins in a histogram — this hides the distribution shape or makes it appear noisy. Use bins='auto' for a starting point.
  • Ignoring outliers found in a box plot — always investigate whether they're data errors or genuine extreme values before deciding to remove them.
  • Plotting when the data contains NaN values, which can cause unexpected gaps in the histogram or missing boxes — clean or drop missing values first.

Variations

  1. Use sns.histplot(..., kde=True) to add a kernel density estimate for a smoother distribution view.
  2. Use sns.boxenplot() (letter-value plot) for a more detailed version of a box plot on large datasets.
  3. Plot horizontal box plots (e.g., plt.boxplot(data, vert=False)) when category labels are long or there are many groups.

Real-world use cases

  • A/B test analysis: compare conversion times between control and test groups using side-by-side box plots to spot outlier sessions.
  • Quality control in manufacturing: plot daily rejection rate histograms to detect shifts in defect distribution over time.
  • Customer segmentation: use box plots of spending per segment to identify high-value outliers and tailor retention campaigns.

Key takeaways

  • Histograms reveal the full shape of a single variable's distribution; box plots condense the distribution into a five-number summary with outlier flags.
  • Bin width is the most important histogram parameter — choose it by balancing smoothness against detail.
  • Box plots are ideal for comparing many groups side by side, while histograms are best for exploring one variable's shape.
  • Seaborn offers convenient one-line functions (histplot, boxplot) with built-in statistical styling and KDE support.
  • Always investigate outliers hinted by box plots — they can signal data errors or crucial business insights.
  • Visualizing your data before modeling is a core data science discipline that prevents costly mistakes downstream.

Sponsored

Sponsored

Discussion

Questions, corrections, and tips help everyone reading this page.

0 comments

Add a comment

Shown publicly with your comment.

Be constructive · max 4,000 characters

No comments yet — start the thread.

Related tutorials, quizzes, and articles for this topic.