Adding a legend is one of the most important steps in making any multi-series plot readable and professional — it clearly labels each line, marker, bar, or area so viewers instantly understand what they're looking at without needing to guess. In 2026, legends are non-negotiable for EDA, presentations, dashboards, and publications.
Here’s a practical guide showing how to add, position, style, and customize legends in Matplotlib (base control), Seaborn (beautiful defaults), and Plotly (interactive & shareable).
1. Basic Setup & Sample Data
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import plotly.express as px
# Realistic time-series data: two related signals
x = np.linspace(0, 10, 100)
y1 = np.sin(x) + np.random.normal(0, 0.2, 100)
y2 = np.cos(x) + np.random.normal(0, 0.2, 100)
df = pd.DataFrame({'x': x, 'Signal A': y1, 'Signal B': y2})
2. Adding Legend with Matplotlib (Full Control)
Use the label= argument in each plot call, then call plt.legend().
plt.figure(figsize=(10, 6))
plt.plot(df['x'], df['Signal A'], label='Signal A (sin + noise)', linewidth=2, color='royalblue')
plt.plot(df['x'], df['Signal B'], label='Signal B (cos + noise)', linewidth=2, color='darkorange', linestyle='--')
plt.title('Two Signals with Legend', fontsize=14, pad=15)
plt.xlabel('Time', fontsize=12)
plt.ylabel('Value', fontsize=12)
plt.grid(True, alpha=0.3, linestyle='--')
# Add legend - most common options
plt.legend(
title='Legend Title', # optional title
loc='upper right', # 'best', 'upper left', 'lower center', etc.
fontsize=10,
frameon=True, # border around legend
fancybox=True,
shadow=True,
ncol=1 # number of columns
)
plt.tight_layout()
plt.show()
3. Adding Legend with Seaborn (Elegant & Automatic)
Seaborn automatically uses hue, style, or size for legends when grouping — very clean.
# Melt for easy hue grouping
df_melt = df.melt(id_vars='x', var_name='Signal', value_name='Value')
plt.figure(figsize=(10, 6))
sns.lineplot(data=df_melt, x='x', y='Value', hue='Signal', linewidth=2.5, palette='deep')
plt.title('Signals by Type with Automatic Legend', fontsize=14)
plt.grid(True, alpha=0.3)
# Customize legend position & style
plt.legend(
title='Signal Type',
loc='upper center',
bbox_to_anchor=(0.5, -0.15), # place below plot
ncol=2,
frameon=True,
fontsize=10
)
plt.tight_layout()
plt.show()
4. Interactive Legend with Plotly (Best for Dashboards & Exploration)
Plotly legends are interactive — click to toggle traces, hover shows info.
fig = px.line(
df_melt, x='x', y='Value', color='Signal',
title='Interactive Signals with Clickable Legend',
labels={'Value': 'Value', 'x': 'Time'},
color_discrete_sequence=['royalblue', 'darkorange']
)
fig.update_layout(
legend_title_text='Signal Type',
legend=dict(
orientation='h', # horizontal legend
yanchor='bottom',
y=1.02,
xanchor='right',
x=1
),
xaxis_title='Time',
yaxis_title='Value',
template='plotly_white',
hovermode='x unified'
)
fig.show()