Box plots

boxplot for quartiles across groups.

A box plot shows the median, quartiles, and whiskers. Outliers are points beyond the whiskers. sns.boxplot is the seaborn version.

Goal

Compare units across cities, then split each city by product.

One grouping

rng = np.random.default_rng(0)
rows = []
for city, loc in [("Nairobi", 12), ("Mombasa", 8), ("Kisumu", 15)]:
    rows.append(
        pd.DataFrame({"city": city, "units": rng.normal(loc, 3, size=30)})
    )
df = pd.concat(rows, ignore_index=True)
sns.boxplot(data=df, x="city", y="units")
plt.title("Units by city")
plt.show()

The line in the box is the median, not the mean.

Hue

rng = np.random.default_rng(0)
rows = []
for city in ["Nairobi", "Mombasa", "Kisumu"]:
    for product, loc in [("A", 10), ("B", 14)]:
        rows.append(
            pd.DataFrame(
                {
                    "city": city,
                    "product": product,
                    "units": rng.normal(loc, 2.5, size=20),
                }
            )
        )
df = pd.concat(rows, ignore_index=True)
sns.boxplot(data=df, x="city", y="units", hue="product")
plt.title("City × product")
plt.show()

Horizontal

rng = np.random.default_rng(1)
df = pd.DataFrame(
    {
        "city": rng.choice(["Nairobi", "Mombasa", "Kisumu", "Nakuru"], size=80),
        "revenue": rng.normal(120, 40, size=80).clip(20),
    }
)
sns.boxplot(data=df, x="revenue", y="city")
plt.title("Revenue (horizontal)")
plt.show()

Swap x and y when category names are long.

You should see

If you also want the shape of the distribution, use a violin plot.