Skip to main content
MahiDev — Learn. Build. Become AI-ready.

Lesson 14

Pair Plots and Joint Plots

Scan every pair of numeric columns at once with sns.pairplot, then zoom in on one pair with sns.jointplot and its histograms along both edges.

Intermediate25 min
Pair Plots and Joint Plots hero Module 26 Lesson 14Pair Plots and Joint Plots hero Module 26 Lesson 14

When a table has several numeric columns, you want to know which of them move together before you pick one chart. pairplot draws a scatter for every pair and a histogram of each column on the diagonal. Once a pair looks interesting, jointplot gives it one large chart with its two distributions along the edges.

A three by three grid of small charts with histograms on the diagonal and scatters elsewhereA three by three grid of small charts with histograms on the diagonal and scatters elsewhere

Every pair at once

pairplot uses every numeric column. With week, hours, and score that is a three by three grid. Each row shares a y axis and each column an x axis, so a panel and its mirror across the diagonal show the same pair flipped.

python
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import seaborn as sns

rng = np.random.default_rng(26)
study = pd.DataFrame({
    "track": rng.choice(["Python", "Data", "Web"], 120),
    "mode": rng.choice(["online", "classroom"], 120),
    "week": rng.integers(1, 7, 120),
})
study["hours"] = (rng.uniform(1, 6, 120) + study["week"] * 0.8).round(1)
study["score"] = (35 + study["hours"] * 4.5 + rng.normal(0, 7, 120)).clip(0, 100).round()

g = sns.pairplot(study, height=2.2)
plt.show()

print(type(g).__name__, g.axes.shape)
print(list(study.select_dtypes("number").columns))

Output:

text
PairGrid (3, 3)
['week', 'hours', 'score']

Colour by group

hue colours every panel by a category and switches the diagonal to density curves so groups of different size can overlap. diag_kind="hist" brings back histograms.

python
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import seaborn as sns

rng = np.random.default_rng(26)
study = pd.DataFrame({
    "track": rng.choice(["Python", "Data", "Web"], 120),
    "mode": rng.choice(["online", "classroom"], 120),
    "week": rng.integers(1, 7, 120),
})
study["hours"] = (rng.uniform(1, 6, 120) + study["week"] * 0.8).round(1)
study["score"] = (35 + study["hours"] * 4.5 + rng.normal(0, 7, 120)).clip(0, 100).round()

sns.pairplot(study, hue="track", height=2.2, plot_kws={"s": 18, "alpha": 0.7})
plt.show()

print(study.groupby("track")[["hours", "score"]].mean().round(1))

Output:

text
        hours  score
track               
Data      7.0   67.2
Python    6.5   64.2
Web       6.3   63.2

Choose columns and drop the mirror

vars= limits the grid to the columns you name. corner=True removes the upper triangle, which repeats the lower one, and kind="reg" adds a trend line to every scatter.

python
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import seaborn as sns

rng = np.random.default_rng(26)
study = pd.DataFrame({
    "track": rng.choice(["Python", "Data", "Web"], 120),
    "mode": rng.choice(["online", "classroom"], 120),
    "week": rng.integers(1, 7, 120),
})
study["hours"] = (rng.uniform(1, 6, 120) + study["week"] * 0.8).round(1)
study["score"] = (35 + study["hours"] * 4.5 + rng.normal(0, 7, 120)).clip(0, 100).round()

g = sns.pairplot(study, vars=["hours", "score"], corner=True, kind="reg", height=2.8)
plt.show()

print(g.axes[0, 1])

Output:

text
None

With corner=True the hidden panels are None, which is what the print shows.

One pair up close with jointplot

jointplot draws one scatter in the middle and each column's histogram along the top and right edges. kind swaps the middle for "reg", "kde", or "hex"; hexagons count dots per area and suit crowded data.

python
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import seaborn as sns

rng = np.random.default_rng(26)
study = pd.DataFrame({
    "track": rng.choice(["Python", "Data", "Web"], 120),
    "mode": rng.choice(["online", "classroom"], 120),
    "week": rng.integers(1, 7, 120),
})
study["hours"] = (rng.uniform(1, 6, 120) + study["week"] * 0.8).round(1)
study["score"] = (35 + study["hours"] * 4.5 + rng.normal(0, 7, 120)).clip(0, 100).round()

g = sns.jointplot(data=study, x="hours", y="score", kind="reg", height=5)
plt.show()

print(type(g).__name__)
print(g.ax_joint.get_xlabel(), g.ax_joint.get_ylabel())

Output:

text
JointGrid
hours score

Groups in a joint plot

With hue, the middle becomes a coloured scatter and the edges become one density curve per group, which shows how the groups differ on each column separately and together.

python
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import seaborn as sns

rng = np.random.default_rng(26)
study = pd.DataFrame({
    "track": rng.choice(["Python", "Data", "Web"], 120),
    "mode": rng.choice(["online", "classroom"], 120),
    "week": rng.integers(1, 7, 120),
})
study["hours"] = (rng.uniform(1, 6, 120) + study["week"] * 0.8).round(1)
study["score"] = (35 + study["hours"] * 4.5 + rng.normal(0, 7, 120)).clip(0, 100).round()

sns.jointplot(data=study, x="hours", y="score", hue="mode", height=5)
plt.show()

print(study.groupby("mode")[["hours", "score"]].median())

Output:

text
           hours  score
mode                   
classroom   7.20   66.0
online      6.55   65.0

Key takeaways

  • pairplot draws every pair of numeric columns, histograms on the diagonal

  • hue colours every panel; vars= picks columns; corner=True drops the mirror

  • jointplot shows one pair with its distributions along the edges

  • jointplot kind="reg", "kde", or "hex" changes the middle chart

  • Next: Themes, Contexts, and Palettes

  • Previous: Regression Plots

Loading playground…

Check your understanding

Pair Plots and Joint Plots Quiz

What does pairplot draw off the diagonal?

1 / 10