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

Lesson 11

Strip, Swarm, and catplot

Show every observation with sns.stripplot and sns.swarmplot, layer the dots over a box plot, and switch any categorical chart with sns.catplot.

Intermediate25 min
Strip, Swarm, and catplot hero Module 26 Lesson 11Strip, Swarm, and catplot hero Module 26 Lesson 11

Box and violin plots summarise. Sometimes you want to see every row. stripplot draws one dot per row along each category, and swarmplot nudges the dots sideways so none overlap. Laid over a box plot, they give both the summary and the evidence.

Dots for every score arranged in three swarms over faint box outlinesDots for every score arranged in three swarms over faint box outlines

One dot per row with stripplot

stripplot adds a little random sideways jitter so dots with equal values do not sit exactly on top of each other. jitter=False lines them up, which shows how much they overlap.

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), sharey=True)
sns.stripplot(data=study, x="track", y="score", jitter=False, ax=axes[0])
axes[0].set_title("jitter=False")
sns.stripplot(data=study, x="track", y="score", jitter=0.25, alpha=0.7, ax=axes[1])
axes[1].set_title("jitter=0.25")
plt.show()

print(study.groupby("track")["score"].count())

Output:

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

No overlaps with swarmplot

swarmplot places each dot next to its neighbours instead of randomly, so the outline of the swarm traces the distribution. It works up to a few hundred rows per group; beyond that there is no room and a strip or violin plot is better.

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.swarmplot(data=study, x="track", y="score", hue="mode", size=4)
plt.show()

print(study.groupby(["track", "mode"]).size().unstack())

Output:

text
mode    classroom  online
track                    
Data           17      17
Python         15      20
Web            22      29

Dots over a box

Draw the box plot first without its outlier dots, then the points on the same axes. A dark single colour keeps the points from competing with the boxes.

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

ax = sns.boxplot(data=study, x="track", y="score", showfliers=False, color="#DDD6FE")
sns.stripplot(data=study, x="track", y="score", color="#1E293B", size=3, alpha=0.7, ax=ax)
plt.show()

print(study.groupby("track")["score"].agg(["min", "median", "max"]))

Output:

text
         min  median   max
track                     
Data    40.0    68.0  85.0
Python  40.0    65.0  85.0
Web     47.0    63.0  85.0

Any categorical chart with catplot

catplot is the figure-level function for the whole categorical family, as relplot is for scatter and line charts. kind picks "strip", "swarm", "box", "violin", "bar", "count", "point", or "boxen", and col or row add facets.

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.catplot(data=study, x="track", y="score", col="mode", kind="box", height=3.4)
plt.show()

print(type(g).__name__, g.axes.shape)

Output:

text
FacetGrid (1, 2)

pointplot for the mean

kind="point" draws only the mean and its interval as a dot with a line, then joins the dots across categories. It makes a change between groups easy to see.

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.catplot(data=study, x="mode", y="score", hue="track", kind="point", height=3.6)
plt.show()

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

Output:

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

Key takeaways

  • stripplot draws one dot per row with a little random jitter

  • swarmplot spreads dots so none overlap; best for hundreds, not thousands

  • Layer points over a box plot drawn with showfliers=False

  • catplot is the figure-level function for every categorical kind

  • Next: Heatmaps

  • Previous: Violin Plots

Loading playground…

Check your understanding

Strip, Swarm, and catplot Quiz

What does stripplot draw?

1 / 10