Strip and swarm

stripplot and swarmplot for every row as a point.

A strip plot draws every row as a point. A swarm plot nudges points so they do not overlap. Use them when the table is small enough to show each sale.

Goal

Show every sale as a point, then dodge by product, then try a swarm.

Strip

df = pd.DataFrame(
    {
        "city": ["Nairobi", "Nairobi", "Mombasa", "Mombasa", "Kisumu", "Kisumu"] * 2,
        "product": ["A", "B"] * 6,
        "units": [12, 7, 9, 4, 11, 3, 10, 8, 6, 5, 14, 2],
        "price": [10.5, 22.0, 10.5, 22.0, 10.5, 22.0] * 2,
    }
)
df["revenue"] = df["units"] * df["price"]
sns.stripplot(data=df, x="city", y="revenue", jitter=True)
plt.title("Every row")
plt.show()

jitter=True spreads points that would otherwise stack on the same x.

Hue

df = pd.DataFrame(
    {
        "city": ["Nairobi", "Nairobi", "Mombasa", "Mombasa", "Kisumu", "Kisumu"] * 2,
        "product": ["A", "B"] * 6,
        "units": [12, 7, 9, 4, 11, 3, 10, 8, 6, 5, 14, 2],
        "price": [10.5, 22.0, 10.5, 22.0, 10.5, 22.0] * 2,
    }
)
df["revenue"] = df["units"] * df["price"]
sns.stripplot(data=df, x="city", y="revenue", hue="product", dodge=True, jitter=True)
plt.title("Dodge by product")
plt.show()

Swarm

rng = np.random.default_rng(0)
df = pd.DataFrame(
    {
        "city": rng.choice(["Nairobi", "Mombasa", "Kisumu"], size=40),
        "units": rng.integers(1, 20, size=40),
    }
)
sns.swarmplot(data=df, x="city", y="units")
plt.title("Swarm")
plt.show()

Swarm is readable up to a few dozen points per group. Past that, seaborn warns and drops points — switch to a violin or box.

Tip

Overlay a strip on a box: call boxplot first with showfliers=False, then stripplot with color="0.2" and a small size.