How to Create a Line Plot in Seaborn

Line plots are the workhorse visualization for continuous data, particularly when you need to show trends over time or relationships between ordered variables. Whether you're analyzing stock prices,...

Key Insights

  • Seaborn’s lineplot() automatically aggregates multiple observations and displays confidence intervals, making it superior to matplotlib for statistical visualizations
  • The hue parameter enables effortless multi-line comparisons by automatically assigning colors and creating legends for categorical variables
  • Combining Seaborn’s high-level interface with matplotlib’s customization functions gives you both convenience and precise control over your visualizations

Introduction to Seaborn Line Plots

Line plots are the workhorse visualization for continuous data, particularly when you need to show trends over time or relationships between ordered variables. Whether you’re analyzing stock prices, temperature changes, or user growth metrics, line plots make patterns immediately visible.

Seaborn builds on matplotlib to provide a more intuitive interface with better default aesthetics. More importantly, sns.lineplot() handles statistical aggregation automatically—if you have multiple observations for the same x-value, Seaborn computes the mean and displays confidence intervals without additional code. This makes it invaluable for exploratory data analysis and presentation-ready visualizations.

Basic Line Plot with sns.lineplot()

The fundamental syntax is straightforward: provide your x-axis variable, y-axis variable, and dataset. Seaborn handles the rest.

import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd

# Create sample data
data = pd.DataFrame({
    'year': [2018, 2019, 2020, 2021, 2022, 2023],
    'revenue': [120, 145, 132, 168, 195, 210]
})

# Create basic line plot
sns.lineplot(data=data, x='year', y='revenue')
plt.show()

You can also pass data directly without a DataFrame:

sns.lineplot(x=data['year'], y=data['revenue'])
plt.show()

Both approaches work, but using the data parameter with column names is cleaner when working with DataFrames and becomes essential when using grouping features.

Customizing Line Appearance

Seaborn provides several parameters to control line aesthetics. The linewidth, linestyle, color, and marker parameters give you precise control over appearance.

# Different line styles
fig, axes = plt.subplots(2, 2, figsize=(12, 8))

# Solid line with markers
sns.lineplot(data=data, x='year', y='revenue', 
             marker='o', markersize=8, ax=axes[0, 0])
axes[0, 0].set_title('With Circle Markers')

# Dashed line
sns.lineplot(data=data, x='year', y='revenue', 
             linestyle='--', linewidth=2.5, ax=axes[0, 1])
axes[0, 1].set_title('Dashed Line')

# Custom color with diamond markers
sns.lineplot(data=data, x='year', y='revenue', 
             color='#e74c3c', marker='D', markersize=7, ax=axes[1, 0])
axes[1, 0].set_title('Custom Color and Markers')

# Dotted line with increased width
sns.lineplot(data=data, x='year', y='revenue', 
             linestyle=':', linewidth=3, ax=axes[1, 1])
axes[1, 1].set_title('Dotted Line')

plt.tight_layout()
plt.show()

Common linestyle options include '-' (solid), '--' (dashed), '-.' (dash-dot), and ':' (dotted). Markers include 'o' (circle), 's' (square), '^' (triangle), 'D' (diamond), and many others from matplotlib.

Multiple Lines and Grouping

The hue parameter is where Seaborn truly shines. It automatically creates separate lines for each category, assigns distinct colors, and generates a legend—all without manual iteration.

# Multi-category dataset
sales_data = pd.DataFrame({
    'quarter': ['Q1', 'Q2', 'Q3', 'Q4'] * 3,
    'revenue': [150, 165, 172, 185, 145, 158, 168, 178, 142, 155, 165, 175],
    'region': ['North'] * 4 + ['South'] * 4 + ['West'] * 4
})

# Create multi-line plot
plt.figure(figsize=(10, 6))
sns.lineplot(data=sales_data, x='quarter', y='revenue', hue='region', 
             marker='o', linewidth=2.5)
plt.title('Quarterly Revenue by Region')
plt.ylabel('Revenue ($K)')
plt.xlabel('Quarter')
plt.show()

You can also use the style parameter to vary line styles by category while keeping colors for another dimension:

# Dataset with two categorical dimensions
complex_data = pd.DataFrame({
    'month': list(range(1, 7)) * 4,
    'sales': [100, 110, 105, 115, 120, 125, 95, 102, 98, 108, 112, 118,
              88, 92, 90, 95, 98, 102, 85, 88, 86, 90, 93, 97],
    'product': ['A'] * 6 + ['B'] * 6 + ['A'] * 6 + ['B'] * 6,
    'channel': ['Online'] * 12 + ['Retail'] * 12
})

plt.figure(figsize=(12, 6))
sns.lineplot(data=complex_data, x='month', y='sales', 
             hue='product', style='channel', markers=True, linewidth=2)
plt.title('Sales by Product and Channel')
plt.show()

Adding Confidence Intervals and Error Bands

When you have multiple observations for the same x-value, Seaborn automatically aggregates them and displays confidence intervals. This is crucial for showing data variability and statistical uncertainty.

# Dataset with multiple observations per time point
np.random.seed(42)
measurements = pd.DataFrame({
    'day': np.repeat(range(1, 11), 5),
    'temperature': np.random.normal(loc=np.repeat(range(20, 30), 5), scale=2),
    'sensor': np.tile(['A', 'B', 'C', 'D', 'E'], 10)
})

plt.figure(figsize=(12, 6))
# Default shows 95% confidence interval
sns.lineplot(data=measurements, x='day', y='temperature')
plt.title('Temperature Measurements with 95% CI')
plt.ylabel('Temperature (°C)')
plt.xlabel('Day')
plt.show()

Control the confidence interval width with the errorbar parameter:

fig, axes = plt.subplots(1, 3, figsize=(15, 5))

# 95% CI (default)
sns.lineplot(data=measurements, x='day', y='temperature', ax=axes[0])
axes[0].set_title('95% Confidence Interval')

# Standard deviation
sns.lineplot(data=measurements, x='day', y='temperature', 
             errorbar='sd', ax=axes[1])
axes[1].set_title('Standard Deviation')

# No error bands
sns.lineplot(data=measurements, x='day', y='temperature', 
             errorbar=None, ax=axes[2])
axes[2].set_title('No Error Bands')

plt.tight_layout()
plt.show()

Advanced Customization

For publication-quality plots, combine Seaborn’s convenience with matplotlib’s fine-grained control. Here’s a fully customized example:

# Create figure with specific size and DPI
fig, ax = plt.subplots(figsize=(12, 7), dpi=100)

# Create the plot
sns.lineplot(data=sales_data, x='quarter', y='revenue', hue='region',
             marker='o', markersize=10, linewidth=3, ax=ax)

# Customize title and labels
ax.set_title('Regional Revenue Performance - 2023', 
             fontsize=18, fontweight='bold', pad=20)
ax.set_xlabel('Quarter', fontsize=14, fontweight='bold')
ax.set_ylabel('Revenue ($K)', fontsize=14, fontweight='bold')

# Customize legend
ax.legend(title='Region', title_fontsize=12, fontsize=11, 
          loc='upper left', frameon=True, shadow=True)

# Add grid for readability
ax.grid(True, alpha=0.3, linestyle='--')

# Customize tick labels
ax.tick_params(labelsize=11)

# Add annotation for highest value
max_idx = sales_data['revenue'].idxmax()
max_row = sales_data.iloc[max_idx]
ax.annotate(f'Peak: ${max_row["revenue"]}K', 
            xy=(max_row['quarter'], max_row['revenue']),
            xytext=(10, 10), textcoords='offset points',
            fontsize=11, fontweight='bold',
            bbox=dict(boxstyle='round,pad=0.5', facecolor='yellow', alpha=0.7),
            arrowprops=dict(arrowstyle='->', connectionstyle='arc3,rad=0'))

plt.tight_layout()
plt.show()

Common Use Cases and Best Practices

Time Series Analysis: Line plots excel at showing temporal patterns. Always ensure your time variable is properly formatted and sorted.

# Real-world example: Stock price analysis
import yfinance as yf

# Download stock data
stock_data = yf.download('AAPL', start='2023-01-01', end='2023-12-31')
stock_data = stock_data.reset_index()

plt.figure(figsize=(14, 7))
sns.lineplot(data=stock_data, x='Date', y='Close', linewidth=2)
plt.title('Apple Stock Price - 2023', fontsize=16, fontweight='bold')
plt.ylabel('Closing Price ($)', fontsize=12)
plt.xlabel('Date', fontsize=12)
plt.xticks(rotation=45)
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()

Best Practices:

  1. Limit the number of lines: More than 5-7 lines becomes difficult to interpret. Consider faceting with sns.relplot() for many categories.

  2. Sort your data: Unsorted data creates zigzag patterns that obscure trends. Always sort by your x-variable.

  3. Use appropriate scales: For exponential growth, consider log scales with ax.set_yscale('log').

  4. Label clearly: Ambiguous axes or missing units make plots useless. Be explicit.

  5. Choose colors wisely: Use colorblind-friendly palettes with palette='colorblind'.

# Faceted approach for many categories
large_dataset = pd.DataFrame({
    'time': list(range(1, 13)) * 6,
    'value': np.random.randn(72).cumsum(),
    'category': np.repeat(['A', 'B', 'C', 'D', 'E', 'F'], 12)
})

# Use relplot for faceting instead of cramming all lines together
g = sns.relplot(data=large_dataset, x='time', y='value', 
                col='category', col_wrap=3, kind='line',
                height=4, aspect=1.2, linewidth=2)
g.set_titles('{col_name}')
plt.show()

Seaborn’s lineplot() strikes the perfect balance between simplicity and power. Start with basic plots for exploration, then layer on customization as you move toward presentation. The automatic statistical aggregation and aesthetic defaults mean you spend less time writing boilerplate code and more time understanding your data.

Liked this? There's more.

Every week: one practical technique, explained simply, with code you can use immediately.