Lesson 06
Histograms with histplot
Show how one column is spread with sns.histplot: choose bins or binwidth, switch stat to percent or density, and compare groups with hue and multiple.
A histogram shows how one column is spread: where most values sit, how wide the range is, and whether it leans to one side. sns.histplot counts the rows in each bin for you, and adds options for comparing groups and switching what the bar height means.
A first histplot
Name one column for x. Seaborn picks a bin count from the data and draws one bar per bin. Each bar is a Matplotlib rectangle, so counting ax.patches tells you how many bins it chose.
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()
ax = sns.histplot(data=study, x="score")
plt.show()
print(len(ax.patches), "bins")
print(study["score"].min(), "to", study["score"].max())Output:
8 bins
40.0 to 85.0bins or binwidth
bins= sets how many bins. binwidth= sets how wide each one is, which gives rounder edges. binrange=(40, 85) fixes where they start and stop. Too few bins hide the shape, too many turn it into noise.
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()
fig, axes = plt.subplots(1, 3, figsize=(12, 3.5), sharey=True)
sns.histplot(data=study, x="score", bins=4, ax=axes[0])
sns.histplot(data=study, x="score", binwidth=5, binrange=(40, 85), ax=axes[1])
sns.histplot(data=study, x="score", bins=40, ax=axes[2])
for ax, name in zip(axes, ["bins=4", "binwidth=5", "bins=40"]):
ax.set_title(name)
plt.show()
print(np.histogram(study["score"], bins=range(40, 90, 5))[0])Output:
[ 2 9 11 19 16 24 19 10 10]What the height means: stat
By default a bar's height is a count. stat="percent" makes all bars add up to 100, stat="probability" to 1, and stat="density" makes the total area 1, which lets groups of different sizes share one axis.
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()
ax = sns.histplot(data=study, x="score", binwidth=5, stat="percent")
plt.show()
print(round(sum(bar.get_height() for bar in ax.patches), 1))Output:
100.0Compare groups with hue and multiple
hue draws one histogram per group. multiple decides how they share the space: "layer" overlaps them, "stack" piles them, "dodge" puts bars side by side, and "fill" stretches each bin to 100% so you see the mix.
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()
fig, axes = plt.subplots(2, 2, figsize=(10, 7))
for ax, how in zip(axes.flat, ["layer", "stack", "dodge", "fill"]):
sns.histplot(data=study, x="score", hue="mode", binwidth=5, multiple=how, ax=ax)
ax.set_title(f"multiple={how!r}")
plt.tight_layout()
plt.show()
print(study["mode"].value_counts())Output:
mode
online 66
classroom 54
Name: count, dtype: int64Add a smooth curve
kde=True draws a smooth estimate of the shape over the bars, and element="step" draws the outline only, which keeps overlapping groups readable.
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.histplot(data=study, x="score", hue="track", element="step", kde=True, binwidth=5)
plt.show()
print(study.groupby("track")["score"].median())Output:
track
Data 68.0
Python 65.0
Web 63.0
Name: score, dtype: float64Key takeaways
-
histplot counts rows per bin for one column
-
bins= sets how many; binwidth= and binrange= set the edges
-
stat="percent" or "density" changes what the height means
-
hue with multiple="layer", "stack", "dodge", or "fill" compares groups
-
Next: KDE and ECDF Plots
-
Previous: relplot and Small Multiples
Loading playground…
Check your understanding
Histograms with histplot Quiz
What does a histogram show?
1 / 10