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

Lesson 08

Count Plots and Bar Plots

Count rows per category with sns.countplot, compare group means with sns.barplot, and read what the thin error bar on each bar tells you.

Intermediate25 min
Count Plots and Bar Plots hero Module 26 Lesson 8Count Plots and Bar Plots hero Module 26 Lesson 8

Seaborn has two bar charts that look alike but answer different questions. countplot asks how many rows each category has. barplot asks what the typical value is in each category: by default the bar is the mean, and a thin line on top shows how certain that mean is.

Bar chart of mean score for each track with error bars on topBar chart of mean score for each track with error bars on top

Count rows with countplot

countplot needs only a category column. The bar heights are the same numbers value_counts prints. order= fixes the bar order.

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.countplot(data=study, x="track", order=["Python", "Data", "Web"])
plt.show()

print(study["track"].value_counts())

Output:

text
track
Web       51
Python    35
Data      34
Name: count, dtype: int64

Compare means with barplot

barplot needs a category and a number. Each bar is that group's mean, the same value groupby prints, and the black line is a 95% confidence interval for it. Overlapping lines mean the difference may be down to chance.

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.barplot(data=study, x="track", y="score", order=["Python", "Data", "Web"])
plt.show()

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

Output:

text
track
Data      67.2
Python    64.2
Web       63.2
Name: score, dtype: float64

Change the estimator and the error bar

estimator changes what the bar measures, for example "median" or "sum". errorbar="sd" shows the spread of the rows, and errorbar=None removes the line when you only want the summary.

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

fig, axes = plt.subplots(1, 2, figsize=(10, 4))
sns.barplot(data=study, x="track", y="score", estimator="median", errorbar=None, ax=axes[0])
axes[0].set_title("median, no error bar")
sns.barplot(data=study, x="track", y="hours", estimator="sum", errorbar=None, ax=axes[1])
axes[1].set_title("total hours")
plt.show()

print(study.groupby("track")["hours"].sum().round(1))

Output:

text
track
Data      238.4
Python    226.9
Web       321.4
Name: hours, dtype: float64

A second grouping with hue

hue splits each bar into side-by-side bars. When colouring by the same column as x, pass it to hue too and turn the legend off; Seaborn 0.13 warns if you give a palette without a hue.

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

fig, axes = plt.subplots(1, 2, figsize=(11, 4))
sns.barplot(data=study, x="track", y="score", hue="mode", ax=axes[0])
sns.barplot(data=study, x="track", y="score", hue="track", palette="pastel",
            legend=False, ax=axes[1])
plt.show()

print(study.pivot_table(index="track", columns="mode", values="score").round(1))

Output:

text
mode    classroom  online
track                    
Data         67.1    67.4
Python       64.9    63.7
Web          64.7    62.1

Horizontal and sorted

Swap the columns, a category on y and a number on x, and the bars turn sideways, which fits long labels. Sorting by the value makes the ranking obvious.

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

ranking = study.groupby("track")["score"].mean().sort_values(ascending=False)
sns.barplot(data=study, y="track", x="score", order=ranking.index, errorbar=None)
plt.show()

print(list(ranking.index))

Output:

text
['Data', 'Python', 'Web']

Key takeaways

  • countplot counts rows per category; barplot summarises a number per category

  • barplot's bar is the mean and its line a 95% confidence interval

  • estimator= changes the summary; errorbar= changes or removes the line

  • Pass hue when you pass palette, and put the category on y for sideways bars

  • Next: Box Plots

  • Previous: KDE and ECDF Plots

Loading playground…

Check your understanding

Count Plots and Bar Plots Quiz

What does countplot show?

1 / 10