Difficulty: Intermediate
Seaborn is a high-level statistical visualization library built on top of Matplotlib. While Matplotlib gives you fine-grained control over every aspect of a plot, Seaborn provides a concise, opinionated API that produces attractive and informative statistical graphics with minimal code. It integrates closely with Pandas DataFrames, meaning you can pass column names directly as axis parameters rather than extracting arrays manually. Seaborn excels at visualizing statistical relationships, distributions, and categorical comparisons, making it the preferred choice for exploratory data analysis in most data science workflows.
One of Seaborn's most appealing features is its built-in theme system. By calling sns.set_theme() at the top of your script, you get a clean, publication-ready aesthetic applied to all subsequent plots. Seaborn offers several preset themes: 'darkgrid' (the default, with a gray background and white gridlines), 'whitegrid' (white background with gridlines, great for quantitative comparisons), 'dark' (gray background without gridlines), 'white' (minimal white background), and 'ticks' (white background with tick marks on the axes). You can further customize with context parameter ('paper', 'notebook', 'talk', 'poster') which scales font sizes and line widths for different presentation contexts.
Heatmaps (sns.heatmap) are one of Seaborn's signature chart types. They display matrix data as a grid of colored cells where the color intensity represents the magnitude of each value. Heatmaps are most commonly used to visualize correlation matrices, where each cell shows the Pearson correlation coefficient between two variables. A well-designed correlation heatmap with annotated values can reveal patterns at a glance: clusters of highly correlated features, potential multicollinearity issues, and candidate features for modeling. You can customize the color palette (diverging palettes like 'coolwarm' or 'RdBu' are ideal for correlation), add annotations with annot=True, and mask the upper triangle since correlation matrices are symmetric.
Pairplots (sns.pairplot) create a grid of scatter plots for every pair of numerical columns in a DataFrame, with histograms or kernel density estimates along the diagonal. This is an incredibly powerful tool for initial data exploration because it lets you see all pairwise relationships simultaneously. The hue parameter colors points by a categorical variable, revealing how different groups separate in each feature space. While pairplots can be slow for datasets with many columns, they are invaluable for datasets with a manageable number of features. The diagonal plots can be configured to show either histograms (diag_kind='hist') or kernel density estimates (diag_kind='kde').
Seaborn also provides specialized distribution plots like sns.histplot, sns.kdeplot, and sns.ecdfplot for univariate analysis, and sns.jointplot for bivariate distributions. For categorical data, sns.boxplot, sns.violinplot, sns.swarmplot, and sns.stripplot offer different perspectives on how a continuous variable varies across categories. Violin plots are particularly useful because they combine the information of a box plot with a kernel density estimate, showing the full shape of the distribution. The catplot function provides a unified interface for all categorical plots with built-in faceting through the col and row parameters.
# Demonstrate Seaborn theme options (no rendering needed)
themes = ['darkgrid', 'whitegrid', 'dark', 'white', 'ticks']
contexts = ['paper', 'notebook', 'talk', 'poster']
palettes = ['deep', 'muted', 'bright', 'pastel', 'dark', 'colorblind']
print("Seaborn Themes:")
for t in themes:
print(f" sns.set_theme(style='{t}')")
print("\nContexts (scales font/line sizes):")
for c in contexts:
print(f" sns.set_theme(context='{c}')")
print("\nBuilt-in palettes:")
for p in palettes:
print(f" sns.set_theme(palette='{p}')")
print("\nRecommended setup:")
print(" sns.set_theme(style='whitegrid', context='notebook', palette='deep')")
Seaborn themes control the overall look. Style affects background and gridlines, context scales elements for different media, and palette sets the color cycle. The 'whitegrid' style with 'notebook' context is a good default for analysis work.
# Compute a correlation matrix manually (what sns.heatmap would visualize)
data = {
'height': [170, 175, 160, 180, 165, 185, 172, 168, 178, 162],
'weight': [70, 80, 55, 90, 60, 95, 75, 65, 85, 52],
'age': [25, 30, 22, 35, 28, 40, 27, 23, 33, 21],
'income': [40, 55, 35, 70, 45, 80, 50, 38, 65, 30]
}
columns = list(data.keys())
n = len(data[columns[0]])
def correlation(x_vals, y_vals):
n = len(x_vals)
mean_x = sum(x_vals) / n
mean_y = sum(y_vals) / n
num = sum((x - mean_x) * (y - mean_y) for x, y in zip(x_vals, y_vals))
den_x = sum((x - mean_x)**2 for x in x_vals) ** 0.5
den_y = sum((y - mean_y)**2 for y in y_vals) ** 0.5
return num / (den_x * den_y) if den_x * den_y != 0 else 0
print("Correlation Matrix (for sns.heatmap):")
header = " " + " ".join(f"{c:>7}" for c in columns)
print(header)
for c1 in columns:
row = f"{c1:>8}"
for c2 in columns:
r = correlation(data[c1], data[c2])
row += f" {r:>7.3f}"
print(row)
print("\nStrong correlations (|r| > 0.8):")
for i, c1 in enumerate(columns):
for j, c2 in enumerate(columns):
if i < j:
r = correlation(data[c1], data[c2])
if abs(r) > 0.8:
print(f" {c1} <-> {c2}: r = {r:.3f}")
This builds a correlation matrix that sns.heatmap(corr_matrix, annot=True, cmap='coolwarm') would visualize. Each cell shows the Pearson correlation between two variables. Values close to 1 or -1 indicate strong relationships. In a heatmap, these would appear as intense red (positive) or blue (negative) cells.
# Pairplot data preparation and summary
species = ['setosa']*4 + ['versicolor']*4 + ['virginica']*4
sepal_length = [5.1, 4.9, 4.7, 5.0, 6.0, 5.9, 6.1, 5.8, 7.0, 6.9, 7.1, 6.8]
sepal_width = [3.5, 3.0, 3.2, 3.6, 2.7, 2.8, 2.9, 2.7, 3.2, 3.1, 3.0, 3.2]
petal_length = [1.4, 1.4, 1.3, 1.4, 4.0, 4.1, 3.9, 4.2, 5.8, 5.7, 5.9, 5.8]
print("Pairplot setup: sns.pairplot(df, hue='species')")
print(f"\nFeatures: sepal_length, sepal_width, petal_length")
print(f"Hue variable: species")
print(f"Grid size: 3x3 (3 features = 9 panels)")
print(f"Diagonal: histograms per species")
print(f"Off-diagonal: scatter plots colored by species")
print("\nPer-species summary:")
for sp in ['setosa', 'versicolor', 'virginica']:
idx = [i for i, s in enumerate(species) if s == sp]
sl = [sepal_length[i] for i in idx]
sw = [sepal_width[i] for i in idx]
pl = [petal_length[i] for i in idx]
print(f" {sp} (n={len(idx)}):")
print(f" sepal_length: mean={sum(sl)/len(sl):.2f}")
print(f" sepal_width: mean={sum(sw)/len(sw):.2f}")
print(f" petal_length: mean={sum(pl)/len(pl):.2f}")
A pairplot creates an NxN grid for N numeric features. Each off-diagonal cell is a scatter plot of two features, colored by the hue variable. The diagonal shows per-group distributions. This summary shows the mean values that would be visible as cluster centers in the pairplot.
# Comparing what different Seaborn categorical plots show
categories = ['Junior', 'Mid', 'Senior']
data_by_cat = {
'Junior': [35, 40, 38, 42, 37, 44, 36, 41],
'Mid': [55, 60, 58, 65, 62, 57, 63, 59],
'Senior': [80, 85, 90, 78, 88, 92, 84, 87]
}
print("Seaborn categorical plots for salary by level:")
print("="*50)
for cat in categories:
vals = data_by_cat[cat]
s = sorted(vals)
n = len(s)
mean = sum(s) / n
median = (s[n//2 - 1] + s[n//2]) / 2 if n % 2 == 0 else s[n//2]
print(f"\n{cat} (n={n}):")
print(f" sns.boxplot: median={median}, range=[{s[0]}, {s[-1]}]")
print(f" sns.barplot: mean={mean:.1f} (with CI error bar)")
print(f" sns.stripplot: {n} individual points shown")
print(f" sns.violinplot: shape shows density, wider at {median}")
print("\nBest choice for this data:")
print(" boxplot - shows spread and outliers concisely")
print(" violinplot - if distribution shape matters")
print(" stripplot - for small datasets (see every point)")
Seaborn provides multiple ways to visualize categorical data. boxplot shows the five-number summary, barplot shows means with confidence intervals, stripplot shows individual observations, and violinplot shows the full distribution shape. Each reveals different aspects of the same data.
seaborn overview, themes, heatmap, pairplot, distributions, categorical plots