Your country

Tools that support it use your country for local currency, number formats, units and paper size. Your choice is saved only in this browser.

Type a name or a two-letter code. Use the up and down arrow keys to move through the countries, Enter to choose one and Escape to close.

Data Analysis with Python (pandas, polars, DuckDB)  Module 10 – Visualising data with matplotlib

Distributions, relationships and correlation charts

Compare distributions with histograms, box plots and ECDFs, show relationships with scatter plots and trend lines, and read correlation heatmaps carefully.

  • Intermediate
  • 40 minutes
  • Examples run with Python 3.14.8, pandas 3.0.6, matplotlib 3.11.2 and seaborn 0.13.2
  • By MySmartCoPilot
Free core, Pro depth: 14 of 40 minutes free
Free: Three charts answer different questions about the same scores · A scatter plot preserves the pair that a fitted line summarises · A correlation matrix is a map to inspect valid pairs. With a pass: 2 in-depth parts and 3 interview answers, about 26 minutes.

What you will learn

  • Compare distributions with histograms, box plots and ECDFs
  • Show relationships with scatter plots, transparency and trend lines
  • Draw and read a correlation heatmap carefully
  • Use seaborn for statistical plots when it saves effort, knowing its maintenance status

Before you start

What you’ll learn · Before you start

What you will learn

  • Compare distributions with histograms, box plots and ECDFs
  • Show relationships with scatter plots, transparency and trend lines
  • Draw and read a correlation heatmap carefully
  • Use seaborn for statistical plots when it saves effort, knowing its maintenance status

Before you start

On this page

Three training groups have forty invented scores each, and two hundred invented flats have paired areas and prices. One average cannot show a score distribution, and two separate averages cannot show which area belongs to which price. A histogram: A chart that groups numeric observations into intervals and represents their counts or density with adjoining bars. groups scores into bins; a box plot: A distribution summary that displays quartiles, a median and whiskers under a stated rule, with any separately drawn observations beyond them. compares medians, quartiles and whiskers; an empirical cumulative distribution function: For each value, the fraction of the observed sample at or below that value. gives the share at or below a value without binning.

For relationships, a scatter plot keeps each pair together. A fitted line summarises linear change, while Pearson correlation: A dimensionless measure of linear association between paired varying measurements, on a scale from minus one to one. measures standardised linear association. Neither proves cause. The examples draw the same score data three ways and the same flats as a scatter plot, so each summary can be compared with the observations it summarises.

Three charts answer different questions about the same scores

The data are invented, from fixed seeds, so that every run gets the same numbers: 40 students in each of three sections, and 200 flats with their area, price, age and distance to a metro station.

lesson_data.py: the invented data Python · lesson_data.py
"""The invented data of this lesson, made from fixed seeds so that every run gets the same numbers."""
import numpy as np
import pandas as pd


def exam_scores() -> pd.DataFrame:
    """Scores out of 100 for three sections of 40 students each."""
    rng = np.random.default_rng(2026)
    a = rng.normal(64, 10, 40)                                        # one broad group
    b = np.concatenate([rng.normal(46, 6, 20), rng.normal(79, 6, 20)])  # two groups of students
    c = 90 - rng.gamma(2.0, 8.0, 40)                                  # most score high, a long tail below
    scores = np.clip(np.concatenate([a, b, c]), 0, 100).round()
    return pd.DataFrame({"section": np.repeat(["A", "B", "C"], 40), "score": scores})


def flats() -> pd.DataFrame:
    """200 flats: floor area in square feet, price in millions, age in years, km to the nearest metro station."""
    rng = np.random.default_rng(7)
    area = rng.uniform(450, 1800, 200).round()
    age = rng.integers(0, 30, 200)
    metro = rng.uniform(0.2, 6.0, 200).round(1)
    price = (0.8 + 0.0058 * area - 0.04 * age - 0.25 * metro + rng.normal(0, 0.6, 200)).round(2)
    return pd.DataFrame({"area": area, "price": price, "age": age, "metro_km": metro})
Three sections as a histogram, a box plot and an ECDF Python · three_views.py
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.ticker import MaxNLocator

from lesson_data import exam_scores

plt.style.use("house.mplstyle")
scores = exam_scores()
groups = {name: g["score"].to_numpy() for name, g in scores.groupby("section")}
styles = {"A": ("#6b7280", "-"), "B": ("#1d5fcb", "--"), "C": ("#1c2027", ":")}

fig, (hist, box, ecdf) = plt.subplots(1, 3, figsize=(8.4, 3.2), layout="constrained")
for name, values in groups.items():
    colour, dash = styles[name]
    hist.hist(values, bins=range(20, 101, 8), histtype="step", color=colour, linestyle=dash, linewidth=2, label=name)
    ecdf.ecdf(values, color=colour, linestyle=dash, label=f"Section {name}")
box.boxplot(list(groups.values()), tick_labels=list(groups), orientation="vertical", widths=0.5)
hist.set(title="Histogram", xlabel="Score", ylabel="Students")
hist.yaxis.set_major_locator(MaxNLocator(integer=True))
box.set(title="Box plot", ylabel="Score")
ecdf.set(title="ECDF", xlabel="Score", ylabel="Share at or below")
ecdf.legend(loc="upper left", fontsize=10)
fig.savefig("three-views.svg", metadata={"Date": None})

print("section  median   Q1    Q3   IQR  lowest  below 50")
for name, values in groups.items():
    q1, median, q3 = np.percentile(values, [25, 50, 75])
    print(f"{name:>7} {median:7.1f} {q1:5.1f} {q3:5.1f} {q3 - q1:5.1f} {values.min():7.0f} {np.mean(values < 50):8.0%}")

Output

section  median   Q1    Q3   IQR  lowest  below 50
      A    63.0  59.0  70.2  11.2      45       2%
      B    67.0  49.5  75.2  25.8      41      25%
      C    76.5  67.5  83.0  15.5      53       0%

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 three_views.py

Scores of sections A, B and C as step histograms, box plots and ECDFs; only the histogram and ECDF show B in two groups.50100Score02468101214StudentsHistogramABC405060708090ScoreBox plot406080Score0.00.20.40.60.81.0Share at or belowECDFSection ASection BSection C

The figure three_views.py draws

Text description of the diagram

Three charts of the same 120 exam scores, 40 per section. Section A is drawn as a solid grey line, section B as a dashed blue line and section C as a dotted dark line.

  • Histogram, bins 8 points wide from 20 to 100: A has one hump around 60 to 68; B has two humps, one in the 40s and one in the high 70s, with few students between them; C rises steadily towards the 80s.
  • Box plot: A's box runs from 59 to 70.2 with the median at 63; B's box is the widest, from 49.5 to 75.2 with the median at 67, and shows nothing of B's two groups; C's box runs from 67.5 to 83 with the median at 76.5.
  • ECDF, the share of students at or below each score: B's curve climbs steeply in the 40s, flattens through the 50s and 60s, then climbs again in the 70s, which is the shape of two groups; C's curve stays lowest until the 70s because most of C scored high.

Distributions show the spread of observations, here forty scores per section. Compare these distributions with three complementary views of the same data. The histogram shows the shape: section A has one hump in the 60s, and section B has two, one in the 40s and one in the high 70s. The box plot compares the sections in one glance: C’s median of 76.5 is the highest, and B’s box, from 49.5 to 75.2, is the widest, but the box says nothing about B’s two groups. The ECDF shows B’s two steep stretches and the gap between them; 25 % of section B is below 50. Reading its lower inverse at 0.5 gives the twentieth ordered observation. For C that is 76, while the usual interpolated sample median averages 76 and 77 to give 76.5. State the percentile convention rather than calling those different calculations identical.

Histogram, box plot or ECDF?
Criterion HistogramBox plotECDF
Shows The shape: humps, gaps, skewMedian, quartiles, range, outliersEvery value, as the share at or below it
Hides Detail inside each binThe shape between the quartilesNothing, but shape is harder to see
A choice you make The bin widthThe whisker ruleNone
Groups at once Two or threeMany, side by sideTwo to four
When to choose The shape of one distributionComparing many groupsPercentiles, and comparing a few groups exactly

Follow section C’s observations into their different summaries.

Interactive · stage by stage Three distribution views on the lesson data Follow section C's observations into their different summaries.
Three distribution views on the lesson data, step 3 of 3. Showing Keep forty scores, Read each summary, State the convention. In focus: State the convention.Keep forty scoresSame observationsRead each summaryBins; box; cumulativeState the conventionC: 76 or 76.5

The drawing shows the whole scene; its 3 steps are listed below.

Every step as text
  1. Keep forty scores. All three views read the same group's observations.
  2. Read each summary. Histogram counts depend on bins; quartiles summarise a box; the ECDF reports cumulative shares.
  3. State the convention. C's lower inverse-CDF p50 is 76; its interpolated median is 76.5.

The calculation’s name and convention are part of the result, especially when two middle observations differ.

Key idea

A histogram shows binned shape, a box summarises quartiles and whiskers, and an ECDF gives cumulative sample shares.

Checkpoint

Check: Three distribution views

  1. Question 1 of 2 Which view avoids choosing histogram bins?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: An ECDF

    It accumulates observed values rather than assigning counts to chosen bins.

  2. Question 2 of 2 Ten of section B's forty scores are below 50. What percentage is that?

    Type a number.

    Show the answer: Question 2 of 2

    Answer: 25 percent

    Ten divided by forty is one quarter, or twenty-five percent.

A scatter plot preserves the pair that a fitted line summarises

For relationships between two numbers of each item, the scatter plot is the chart. Here each of the 200 flats is a dot placed by its area and its price, with a straight trend line fitted by least squares:

Price against area, with a fitted line Python · scatter_trend.py
import matplotlib.pyplot as plt
import numpy as np

from lesson_data import flats

plt.style.use("house.mplstyle")
homes = flats()
slope, intercept = np.polyfit(homes["area"], homes["price"], deg=1)   # highest power first
r = homes["area"].corr(homes["price"])

fig, ax = plt.subplots()
ax.scatter(homes["area"], homes["price"], s=16, alpha=0.6, color="#1d5fcb")
xs = np.array([450, 1800])
ax.plot(xs, intercept + slope * xs, color="#1c2027", linewidth=2)
ax.set(xlabel="Floor area (square feet)", ylabel="Price (millions)")
ax.set_title(f"About {slope * 100:.2f} million more per 100 square feet")
fig.savefig("scatter-trend.svg", metadata={"Date": None})

print(f"trend line: price = {intercept:.2f} + {slope:.5f} x area")
print(f"Pearson correlation r = {r:.2f}, so r squared = {r * r:.2f}")
print(f"the line's price for 1,000 square feet: {intercept + slope * 1000:.2f} million")

Output

trend line: price = -0.72 + 0.00586 x area
Pearson correlation r = 0.95, so r squared = 0.91
the line's price for 1,000 square feet: 5.15 million

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 scatter_trend.py

Price against floor area for 200 flats, rising almost in a straight line, with the fitted trend line drawn through them.5007501000125015001750Floor area (square feet)246810Price (millions)About 0.59 million more per 100 square feet

The chart scatter_trend.py draws

Text description of the diagram

A scatter plot of 200 invented flats: floor area from 455 to 1,794 square feet on the x-axis, price in millions on the y-axis, each flat a semi-transparent blue dot.

The dots rise from about 1 to 3 million for the smallest flats to about 9 to 10 million for the largest, in a band roughly 1.5 million wide. A dark trend line, fitted with np.polyfit, runs through the middle of the band: price = −0.72 + 0.00586 × area, about 0.59 million more for every 100 square feet. The correlation is r = 0.95.

np.polyfit(x, y, deg=1) returns the coefficients highest power first, so the slope comes before the intercept: each extra square foot adds 0.00586 million on average, about 0.59 million per 100 square feet. The correlation, r = 0.95, says how strongly the two variables move together linearly after their scales are standardised, from −1 to +1. It does not measure prediction error in millions: changing the currency changes those distances while leaving r unchanged. Three tools help when scatter plots get harder. Transparency (alpha) draws points partly see-through, so places where many overlap look darker. hexbin counts the points in hexagonal cells and shades each cell by its count. Polynomial.fit from numpy.polynomial fits the same line, and NumPy’s documentation recommends it for new code because it is numerically more stable.

Follow the flat observations before interpreting the fitted line’s number.

Interactive · stage by stage Paired points and linear fit on the lesson data Follow the flat observations before interpreting the fitted line's number.
Paired points and linear fit on the lesson data, step 3 of 3. Showing Place two hundred pairs, Fit a summary, Keep distinct meanings. In focus: Keep distinct meanings.Place two hundred pairsArea and priceFit a summarySlope and interceptKeep distinct meaningsr versus residuals

The drawing shows the whole scene; its 3 steps are listed below.

Every step as text
  1. Place two hundred pairs. Each flat is located by its paired measurements.
  2. Fit a summary. Least squares fits one straight line in the stated measurement units.
  3. Keep distinct meanings. Correlation standardises scales; a residual retains price units and assesses prediction error.

A high r is not a price-per-square-foot estimate or a measure of error in millions.

Key idea

Keep each area-price pair, and distinguish a unit-bearing slope or residual from dimensionless correlation.

Checkpoint

Check: Paired points and linear fit

  1. Question 1 of 2 What does one flat's scatter point preserve?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: Its area and its own price together

    Both coordinates belong to the same observation.

  2. Question 2 of 2 Prices are converted from millions to full currency units. What can stay unchanged?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: Pearson r

    A positive scaling changes units and distances while preserving standardised linear association.

A correlation matrix is a map to inspect valid pairs

Correlation charts compare columns in pairs to show which move together. These correlation charts summarise association rather than cause. Their numbers come from DataFrame.corr():

The correlation matrix of the flats Python · corr_matrix.py
from lesson_data import flats

homes = flats()
print(homes.corr().round(2))
print()
print("strongest with price:", homes.corr()["price"].drop("price").abs().idxmax())

Output

          area  price   age  metro_km
area      1.00   0.95  0.02      0.01
price     0.95   1.00 -0.13     -0.14
age       0.02  -0.13  1.00      0.04
metro_km  0.01  -0.14  0.04      1.00

strongest with price: area

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 corr_matrix.py

A heatmap colours each cell of this matrix, so a table of 30 columns, 435 pairs, can be scanned in seconds. The diagonal is 1 for nonconstant columns with enough paired observations. A constant or all-missing column instead has undefined correlations, which pandas represents as NaN. The matrix is symmetric, so half of it repeats the other half. Read correlation charts with care: Pearson’s r summarises standardised linear association, so a strong curve can score near 0, one far point can create a large r on its own, and none of it says which column causes which. Here area is the only strong partner of price, while age and the distance to the metro pull the price down only slightly.

seaborn builds on matplotlib and draws each of these statistical charts in one call, with grouping by a column and a legend built in. Its most recent release is 0.13.2, and it still works with pandas 3, so it is worth using when it saves code; the charts in this lesson use matplotlib directly, which does not depend on seaborn’s release pace.

Trace a Pearson cell from row pairs to its meaning.

Interactive · stage by stage Pairwise correlation on the lesson data Trace a Pearson cell from row pairs to its meaning.
Pairwise correlation on the lesson data, step 3 of 3. Showing Select a pair, Check variation, Inspect the plot. In focus: Inspect the plot.Select a pairTwo numeric columnsCheck variationConstants are undefinedInspect the plotAssociation, not cause

The drawing shows the whole scene; its 3 steps are listed below.

Every step as text
  1. Select a pair. Use the same row's values only when both are observed.
  2. Check variation. A constant or all-missing Pearson column has undefined correlations.
  3. Inspect the plot. A matrix cell points to a scatter plot and an investigation rather than a causal conclusion.

The valid pair count and the pattern behind the cell matter as much as its displayed colour.

Key idea

Pairwise-complete data and varying columns matter; a heatmap cannot settle a causal claim.

Checkpoint

Check: Pairwise correlation

  1. Question 1 of 2 How does DataFrame.corr handle missing values for Pearson pairs?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: It uses observations present in both columns

    Each pair has its own complete observations, which can make pair counts differ.

  2. Question 2 of 2 A numeric column contains only seven. What should its Pearson diagonal represent?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: An undefined correlation, shown as NaN

    A constant has no variance for Pearson's denominator; the ordinary Pearson path does not force a valid one.

What each distribution chart can hide, reproduced Pro: opens with a Pro, Premium or Ultimate pass

Every distribution chart makes a choice for you: the bin width, the whisker rule, the definition of a percentile. This part reproduces what each choice can hide, works one box plot out by hand, and reads exact percentiles off an ECDF.

In this part:

  • Changing bins can merge or split the same observed groups
  • Identical box summaries can hide very different score locations
  • Whiskers stop at observed scores within their fences
  • Percentile methods can return different valid sample summaries

6 diagrams · 4 runnable examples (Python) · about 9 minutes

Opening this part with your pass…

This part opens with any MySmartCoPilot pass.

  • Pro pass · 1 week₹79$2.99
  • 30 days₹179$5.99
  • 1 year₹1,699$45

One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.

It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).

Scatter plots, trend lines and correlation heatmaps without the traps Pro: opens with a Pro, Premium or Ultimate pass

Relationship charts fail in quieter ways: points hide each other, lines run past the data, and a correlation misses the shape. This part measures each failure, shows the chart or the number that catches it, and then draws the whole panel in seaborn.

In this part:

  • Opacity saturates before a dense scatter plot reveals its counts
  • A fitted line needs its observed range and residual scale
  • Ranks and linear correlation summarise different patterns
  • A fixed minus-one to one scale preserves correlation colour meaning
  • A plotting wrapper still depends on its underlying API versions
  • Your turn: a 2 × 2 exploration panel, checked by its objects

5 diagrams · 7 runnable examples (Python) · about 11 minutes

Opening this part with your pass…

This part opens with any MySmartCoPilot pass.

  • Pro pass · 1 week₹79$2.99
  • 30 days₹179$5.99
  • 1 year₹1,699$45

One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.

It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).

Practice

Read the score summaries and paired flat measurements before answering. Distinguish a plotted percentile from an interpolated median and a correlation from a causal claim.

Practice that adapts to you

Practise this lesson

6 questions about 12 ideas of this lesson. Each answer is explained at once, and what you get right is kept in this browser.

  1. Question 1 of 6 Section B's box runs from 49.5 to 75.2 with the median at 67. What can this box plot not show?

    Choose one answer.

    Show the answer: Question 1 of 6

    Answer: That most of the section's students form two groups, one in the 40s and one in the high 70s

    A box plot draws five numbers: the whisker ends, the two quartiles and the median. Two groups of students with a gap between them give a wide box, but nothing in the box says that the middle of it is almost empty. The histogram and the ECDF of the same scores show the two groups.

  2. Question 2 of 6 How do you read the lower 50th percentile, using the inverse empirical CDF convention, from an ECDF?

    Choose one answer.

    Show the answer: Question 2 of 6

    Answer: Find where the curve reaches 0.5 on the vertical axis and read the value below it

    An ECDF plots the share of data at or below each value. Its lower inverse at 0.5 is the first value where the curve reaches that share. For an even sample this can differ from the conventional median that averages the two middle values. A steep stretch marks many nearby observations, rather than the 50th percentile.

  3. Question 3 of 6 Area and price of 200 flats have a correlation of r = 0.95. Which statement does that number support?

    Choose one answer.

    Show the answer: Question 3 of 6

    Answer: There is strong positive linear association on standardised scales

    Pearson r measures standardised linear association. It is unchanged by a positive change of measurement unit, while the slope and residual distances change. It is neither a causal effect, a share of flats nor a price-per-area coefficient.

  4. Question 4 of 6 For another report: which view avoids choosing histogram bins?

    Choose one answer.

    Show the answer: Question 4 of 6

    Answer: An ECDF

    It accumulates observed values rather than assigning counts to chosen bins.

  5. Question 5 of 6 For another report: what does one flat's scatter point preserve?

    Choose one answer.

    Show the answer: Question 5 of 6

    Answer: Its area and its own price together

    Both coordinates belong to the same observation.

  6. Question 6 of 6 For another report: how does DataFrame.corr handle missing values for Pearson pairs?

    Choose one answer.

    Show the answer: Question 6 of 6

    Answer: It uses observations present in both columns

    Each pair has its own complete observations, which can make pair counts differ.

Interview questions

  1. Fresher · Warm-up

    When would you show a distribution as a box plot rather than a histogram, and what can a box plot hide?

    Use a box plot when you compare many groups at once. One narrow column per group shows the median, the middle half of the values and the extremes, so ten groups fit side by side on one scale, where ten histograms would need ten panels or would overlap into a tangle. A histogram is better for one or two groups when the shape matters: whether the values form one hump or two, or whether there is a long tail of large values. That shape is what a box plot can hide. Two groups of values with a gap between them give a wide box, and nothing in the box shows the gap. When a box is unusually wide, draw the histogram or the ECDF beside it.

  2. Fresher to mid

    Two analysts plot the same 400 delivery times. One histogram shows one peak, the other shows two. Who is right, and how do you decide what to show the operations team?

    Model answer, Pro. Model answers open with any pass; prices are in the notice on this page. First step and follow-ups

  3. Mid to senior

    A correlation heatmap of 30 product metrics shows r = 0.02 between discount depth and units sold, and a manager concludes that discounts do not affect sales. What do you check before agreeing, and what do you show instead?

    Model answer, Pro. First step and follow-ups

  4. Mid to senior

    A scatter plot of 2 million orders, order value against delivery time, is one solid blob. How do you show the relationship, and how do you check whether a trend line through it means anything?

    Model answer, Pro. First step and follow-ups

Key takeaways

  • A histogram shows a distribution’s shape, a box plot compares many groups, and an ECDF shows every value and its percentiles without bins.
  • A scatter plot shows a relationship; np.polyfit returns the slope first, and r measures standardised linear association rather than prediction error in the measured unit.
  • A Pearson correlation chart summarises linear association for each valid pair, so inspect curves, missing pairs and extreme observations before interpreting it.
  • seaborn draws these charts in fewer lines on top of matplotlib.

Terms in this lesson

box plot
A distribution summary that displays quartiles, a median and whiskers under a stated rule, with any separately drawn observations beyond them.
empirical cumulative distribution function
For each value, the fraction of the observed sample at or below that value.
histogram
A chart that groups numeric observations into intervals and represents their counts or density with adjoining bars.
Pearson correlation
A dimensionless measure of linear association between paired varying measurements, on a scale from minus one to one.

Corrections

  • Added scenes, checkpoints and adaptive practice; clarified correlation and percentile limits while retaining the score and flat data, chart programs and Figure worksheet.

References

Related tools

Report a problem with this lesson

Quick answers and tool search

Type to search tools or to get a quick answer, for example 18% of 2500. Use the up and down arrow keys to move through the results, Enter to choose, and Escape to close.