Scatter Plot Matrix — Seaborn

A grid of scatter plots showing all pairwise relationships between multiple variables, with histograms or kernel density estimates on the diagonal. This comprehensive visualization enables simultaneous exploration of correlations and distributions across an entire dataset, making it invaluable for understanding multivariate data structure at a glance. Also known as a pairplot or SPLOM (Scatter Plot Matrix).

Scatter Plot Matrix rendered with Seaborn

Python source (Seaborn)

""" anyplot.ai
scatter-matrix: Scatter Plot Matrix
Library: seaborn 0.13.2 | Python 3.13.13
Quality: 92/100 | Updated: 2026-05-09
"""

import os

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


# Theme tokens
THEME = os.getenv("ANYPLOT_THEME", "light")
PAGE_BG = "#FAF8F1" if THEME == "light" else "#1A1A17"
ELEVATED_BG = "#FFFDF6" if THEME == "light" else "#242420"
INK = "#1A1A17" if THEME == "light" else "#F0EFE8"
INK_SOFT = "#4A4A44" if THEME == "light" else "#B8B7B0"

# Okabe-Ito palette
IMPRINT = ["#009E73", "#C475FD", "#4467A3"]

# Data: Financial metrics across market segments
np.random.seed(42)
n_samples = 120

# Three market segments
segments = np.repeat(["Growth", "Value", "Dividend"], n_samples // 3)

# Generate financial metrics with realistic distributions
data = {
    "Annual Return (%)": np.concatenate(
        [
            np.random.exponential(8, n_samples // 3) + 15,  # Growth: high return
            np.random.exponential(5, n_samples // 3) + 8,  # Value: moderate return
            np.random.exponential(4, n_samples // 3) + 5,  # Dividend: steady return
        ]
    ),
    "Volatility (%)": np.concatenate(
        [
            np.random.exponential(3, n_samples // 3) + 18,  # Growth: high volatility
            np.random.exponential(2, n_samples // 3) + 12,  # Value: medium volatility
            np.random.exponential(1.5, n_samples // 3) + 8,  # Dividend: low volatility
        ]
    ),
    "P/E Ratio": np.concatenate(
        [
            np.random.exponential(5, n_samples // 3) + 22,  # Growth: high multiples
            np.random.exponential(3, n_samples // 3) + 12,  # Value: low multiples
            np.random.exponential(2, n_samples // 3) + 16,  # Dividend: moderate multiples
        ]
    ),
    "Dividend Yield (%)": np.concatenate(
        [
            np.random.exponential(0.4, n_samples // 3) + 0.5,  # Growth: low yield
            np.random.exponential(0.6, n_samples // 3) + 1.5,  # Value: moderate yield
            np.random.exponential(0.8, n_samples // 3) + 3.5,  # Dividend: high yield
        ]
    ),
    "Segment": segments,
}

df = pd.DataFrame(data)

# Set theme for the entire figure
sns.set_theme(
    style="whitegrid",
    rc={
        "figure.facecolor": PAGE_BG,
        "axes.facecolor": PAGE_BG,
        "axes.edgecolor": INK_SOFT,
        "axes.labelcolor": INK,
        "text.color": INK,
        "xtick.color": INK_SOFT,
        "ytick.color": INK_SOFT,
        "grid.color": INK,
        "grid.alpha": 0.10,
        "grid.linewidth": 0.8,
        "legend.facecolor": ELEVATED_BG,
        "legend.edgecolor": INK_SOFT,
    },
)

sns.set_context("talk", font_scale=1.2)

# Create pairplot with scatter matrices
g = sns.pairplot(
    df,
    hue="Segment",
    palette=IMPRINT,
    diag_kind="kde",
    plot_kws={"s": 60, "alpha": 0.7, "edgecolor": PAGE_BG, "linewidth": 0.5},
    diag_kws={"linewidth": 2.5, "fill": True, "alpha": 0.4},
    corner=False,
    height=2.8,
    aspect=1.0,
)

# Update title
g.figure.suptitle("scatter-matrix · seaborn · anyplot.ai", fontsize=28, y=1.00, fontweight="medium")

# Update legend using seaborn's move_legend (non-private API)
if g._legend is not None:
    g._legend.set_title("Segment")
    g._legend.get_title().set_fontsize(16)
    for text in g._legend.get_texts():
        text.set_fontsize(14)

# Adjust label sizes
for ax in g.axes.flatten():
    if ax is not None:
        ax.tick_params(axis="both", labelsize=13)
        xlabel = ax.get_xlabel()
        ylabel = ax.get_ylabel()
        if xlabel:
            ax.set_xlabel(xlabel, fontsize=16, color=INK)
        if ylabel:
            ax.set_ylabel(ylabel, fontsize=16, color=INK)

plt.tight_layout()
g.figure.savefig(f"plot-{THEME}.png", dpi=300, bbox_inches="tight", facecolor=PAGE_BG)

Part of Scatter Plot Matrix on anyplot.ai.

Other implementations