Line plots

lineplot with hue, markers, and ordered categories.

sns.lineplot connects values along x. With hue, each group gets its own line. Order categorical months yourself or seaborn will sort alphabetically.

Goal

Plot rainfall by month for three cities, with markers and an ordered x-axis.

One series

df = pd.DataFrame(
    {
        "month": ["Jan", "Feb", "Mar", "Apr"],
        "rain": [50, 40, 80, 150],
    }
)
sns.lineplot(data=df, x="month", y="rain", marker="o")
plt.ylabel("mm")
plt.title("Nairobi rainfall")
plt.show()

Hue by city

df = pd.DataFrame(
    {
        "month": ["Jan", "Feb", "Mar", "Apr"] * 3,
        "city": ["Nairobi"] * 4 + ["Mombasa"] * 4 + ["Kisumu"] * 4,
        "rain": [50, 40, 80, 150, 20, 15, 30, 90, 70, 80, 120, 180],
    }
)
df["month"] = pd.Categorical(
    df["month"], categories=["Jan", "Feb", "Mar", "Apr"], ordered=True
)
sns.lineplot(data=df, x="month", y="rain", hue="city", marker="o")
plt.ylabel("mm")
plt.title("Rainfall by city")
plt.show()

Without the Categorical, April can appear before February because "Apr" < "Feb" as text.

Error band

rng = np.random.default_rng(0)
rows = []
for city, mean in [("Nairobi", 80), ("Mombasa", 40), ("Kisumu", 110)]:
    for month in ["Jan", "Feb", "Mar", "Apr"]:
        for _ in range(6):
            rows.append(
                {
                    "city": city,
                    "month": month,
                    "rain": mean + rng.normal(0, 12),
                }
            )
df = pd.DataFrame(rows)
df["month"] = pd.Categorical(
    df["month"], categories=["Jan", "Feb", "Mar", "Apr"], ordered=True
)
sns.lineplot(data=df, x="month", y="rain", hue="city", marker="o")
plt.ylabel("mm")
plt.title("Mean with 95% CI")
plt.show()

Several rows per city–month make seaborn draw a confidence interval around the mean. Pass errorbar=None to hide it.

Pitfall

lineplot aggregates duplicate x values. If you already have one row per point, that is fine — there is nothing to average.