Adding and Customizing Legends in Pandas & Seaborn Plots
A well-designed legend is essential for making your plots clear and professional. In 2026, properly customizing legends in Pandas and Seaborn helps viewers quickly understand what each line, bar, or marker represents, especially when layering multiple series or using the hue parameter.
TL;DR — Key Legend Techniques
- Use
label=when plotting multiple series - Use
plt.legend()to control position, title, and style - Use
huein Seaborn for automatic legends - Place legends outside the plot when space is limited
1. Basic Legend with Pandas Plot
import pandas as pd
import matplotlib.pyplot as plt
# Create a small demo file so this example runs as-is
# (in your project, sales_data.csv is your real export)
import numpy as np
rng = np.random.default_rng(42)
n = 60
pd.DataFrame({
"order_date": pd.date_range("2026-01-01", periods=n, freq="3D"),
"customer_id": rng.integers(101, 121, n),
"customer_name": rng.choice([" ana", "ben ", "chen", "dana"], n),
"product_id": rng.integers(1, 9, n),
"region": rng.choice(["North", "South", "East", "West"], n),
"category": rng.choice(["Electronics", "Computers", "Books", "Home"], n),
"payment_method": rng.choice(["card", "cash", "wallet"], n),
"segment": rng.choice(["consumer", "business"], n),
"quantity": rng.integers(1, 6, n),
"amount": rng.uniform(50, 2500, n).round(2),
"discount": rng.choice([0.0, 0.05, 0.1, 0.2], n),
}).assign(
price=lambda d: (d["amount"] / d["quantity"]).round(2),
profit=lambda d: (d["amount"] * rng.uniform(0.05, 0.3, n)).round(2),
).assign(
ship_date=lambda d: d["order_date"] + pd.Timedelta(days=2),
status=lambda d: np.where(d["amount"] > 2000, "priority", "standard"),
).to_csv("sales_data.csv", index=False)
df = pd.read_csv("sales_data.csv", parse_dates=["order_date"])
monthly = df.resample("ME", on="order_date").agg({"amount": "sum", "quantity": "sum"}).reset_index()
plt.figure(figsize=(11, 6))
plt.plot(monthly["order_date"], monthly["amount"], label="Total Sales", linewidth=2.5)
plt.plot(monthly["order_date"], monthly["quantity"], label="Total Quantity", linewidth=2.5)
plt.title("Monthly Sales and Quantity Trend")
plt.ylabel("Value")
plt.xlabel("Date")
plt.legend(title="Metrics", fontsize=10, title_fontsize=11)
plt.grid(True, alpha=0.3)
plt.show()
2. Professional Legend with Seaborn
import seaborn as sns
plt.figure(figsize=(12, 7))
sns.lineplot(
data=df,
x="order_date",
y="amount",
hue="region",
linewidth=2.2,
marker="o",
markersize=5
)
plt.title("Sales Trends by Region")
plt.ylabel("Sales Amount")
plt.xlabel("Date")
# Customizing the legend
plt.legend(
title="Region",
title_fontsize=12,
fontsize=10,
loc="upper left",
bbox_to_anchor=(1.02, 1), # Place legend outside the plot
frameon=True
)
plt.tight_layout()
plt.show()
3. Advanced Legend Customization
plt.figure(figsize=(10, 6))
sns.scatterplot(
data=df,
x="quantity",
y="amount",
hue="region",
size="profit",
alpha=0.7
)
plt.title("Quantity vs Amount by Region")
plt.legend(
title="Region & Profit",
bbox_to_anchor=(1.05, 1),
loc='upper left',
ncol=1, # Single column legend
frameon=True,
shadow=True
)
plt.tight_layout()
plt.show()
4. Best Practices for Legends in 2026
- Always add a meaningful
titleto your legend - Use
bbox_to_anchor=(1.02, 1)to place legends outside the plot when space is tight - Use
fontsizeandtitle_fontsizeto control readability - Keep the number of legend items reasonable (ideally ≤ 8)
- Use
plt.tight_layout()after adjusting legend position - For Seaborn plots with
hue, customize the legend after plotting
Making Legends Useful
A legend explains what each colour or line means, so it must use readable names and never hide data. Labels come from the label= argument, from DataFrame column names, or from the hue column in seaborn.
Control placement with loc="best" or move the legend outside the axes with bbox_to_anchor. Give it a title, and remove it when a single series is already explained by the chart title.
Worked Example: Placing a Legend Outside
Three product lines are plotted with a titled legend placed to the right of the chart.
import pandas as pd
import matplotlib.pyplot as plt
df = pd.DataFrame({
"Books": [30, 35, 40, 38],
"Home": [50, 48, 55, 60],
"Computers": [20, 28, 26, 35],
}, index=["Q1", "Q2", "Q3", "Q4"])
fig, ax = plt.subplots(figsize=(8, 4))
df.plot(ax=ax, marker="o")
ax.legend(title="Category", loc="upper left", bbox_to_anchor=(1.02, 1))
ax.set_ylabel("Revenue (USD thousands)")
fig.tight_layout()
print([t.get_text() for t in ax.get_legend().get_texts()])
pandas uses the column names as legend labels automatically. bbox_to_anchor moves the box just outside the right edge, and tight_layout makes room for it.
Common Mistakes
- Leaving default labels such as _child0.
- Placing the legend over important data.
- Adding a legend to a chart with one series.
- Using cryptic column names as labels.
Quick Summary
- Labels come from label=, column names or hue.
- Use loc and bbox_to_anchor for placement.
- Add a legend title for clarity.
- Remove legends that add nothing.
Conclusion
A good legend can make or break the clarity of your visualization. In 2026, spending a little extra time customizing legends with proper titles, positioning, and styling significantly improves the professionalism and readability of your plots. Whether using Pandas .plot() or Seaborn, always ensure your legend clearly communicates what each element represents.
Next steps:
- Review your existing plots and improve their legends by adding titles, adjusting position, and using
bbox_to_anchorwhen needed