Basic Parallel Coordinates Plot — plotnine

A parallel coordinates plot visualizes multivariate data by representing each variable as a vertical axis and each observation as a line connecting values across all axes. This technique is powerful for identifying patterns, clusters, and outliers in high-dimensional datasets where traditional 2D plots fall short. It enables simultaneous comparison of multiple variables for each data point.

Basic Parallel Coordinates Plot rendered with plotnine

Python source (plotnine)

""" anyplot.ai
parallel-basic: Basic Parallel Coordinates Plot
Library: plotnine 0.15.7 | Python 3.13.14
Quality: 86/100 | Updated: 2026-07-24
"""

import os

import numpy as np
import pandas as pd
from plotnine import (
    aes,
    annotate,
    element_blank,
    element_line,
    element_rect,
    element_text,
    geom_line,
    geom_point,
    geom_vline,
    ggplot,
    labs,
    scale_color_manual,
    scale_x_continuous,
    theme,
    theme_minimal,
)


# 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"

IMPRINT = ["#009E73", "#C475FD", "#4467A3", "#BD8233", "#AE3030", "#2ABCCD", "#954477"]

# Data — synthetic iris-like measurements, 50 samples per species (balanced)
np.random.seed(42)
n = 50
cov_setosa = np.diag([0.25, 0.09, 0.25, 0.04])
cov_versicol = np.diag([0.25, 0.09, 0.25, 0.04])
cov_virginica = np.diag([0.25, 0.09, 0.25, 0.04])
setosa = np.random.multivariate_normal([5.01, 3.42, 1.46, 0.24], cov_setosa, size=n)
versicol = np.random.multivariate_normal([5.94, 2.77, 4.26, 1.33], cov_versicol, size=n)
virginica = np.random.multivariate_normal([6.59, 2.97, 5.55, 2.03], cov_virginica, size=n)

cols = ["sepal_length", "sepal_width", "petal_length", "petal_width"]
df = pd.DataFrame(np.vstack([setosa, versicol, virginica]), columns=cols)
df["species"] = ["Setosa"] * n + ["Versicolor"] * n + ["Virginica"] * n
df["id"] = range(len(df))

# Clip to realistic ranges
df["sepal_length"] = df["sepal_length"].clip(4.0, 8.5)
df["sepal_width"] = df["sepal_width"].clip(2.0, 4.5)
df["petal_length"] = df["petal_length"].clip(1.0, 7.0)
df["petal_width"] = df["petal_width"].clip(0.1, 2.8)

# Normalize each dimension to 0–1 scale for fair comparison
dimensions = ["sepal_length", "sepal_width", "petal_length", "petal_width"]
df_norm = df.copy()
for col in dimensions:
    df_norm[col] = (df[col] - df[col].min()) / (df[col].max() - df[col].min())

# Transform to long format for parallel coordinates
df_long = pd.melt(df_norm, id_vars=["id", "species"], value_vars=dimensions, var_name="dimension", value_name="value")
dim_map = {dim: i for i, dim in enumerate(dimensions)}
df_long["dim_num"] = df_long["dimension"].map(dim_map)

# Imprint palette colors — first series always #009E73
species_order = ["Setosa", "Versicolor", "Virginica"]
colors = {sp: IMPRINT[i] for i, sp in enumerate(species_order)}

# Plot
plot = (
    ggplot(df_long, aes(x="dim_num", y="value", group="id", color="species"))
    + geom_vline(xintercept=list(range(len(dimensions))), color=INK_SOFT, size=0.5, alpha=0.4)
    + geom_line(alpha=0.35, size=1.0)
    + geom_point(size=2.5, alpha=0.55)
    + annotate(
        "text",
        x=2.5,
        y=0.32,
        label="Setosa separates cleanly on petal dimensions",
        color=IMPRINT[0],
        size=7,
        ha="center",
        fontstyle="italic",
    )
    + scale_color_manual(values=colors, breaks=species_order)
    + scale_x_continuous(
        breaks=list(range(len(dimensions))),
        labels=["Sepal Length\n(cm)", "Sepal Width\n(cm)", "Petal Length\n(cm)", "Petal Width\n(cm)"],
    )
    + labs(
        x="Dimension", y="Normalized Value (0–1)", title="parallel-basic · plotnine · anyplot.ai", color="Iris Species"
    )
    + theme_minimal()
    + theme(
        figure_size=(8, 4.5),
        plot_background=element_rect(fill=PAGE_BG, color=PAGE_BG),
        panel_background=element_rect(fill=PAGE_BG),
        panel_border=element_blank(),
        panel_grid_major=element_line(color=INK, size=0.3, alpha=0.10),
        panel_grid_minor=element_blank(),
        axis_title=element_text(color=INK, size=10),
        axis_text=element_text(color=INK_SOFT, size=8),
        axis_line=element_line(color=INK_SOFT, size=0.4),
        plot_title=element_text(color=INK, size=12),
        legend_background=element_rect(fill=ELEVATED_BG, color=INK_SOFT),
        legend_text=element_text(color=INK_SOFT, size=8),
        legend_title=element_text(color=INK, size=9),
        text=element_text(size=8),
    )
)

# Save
plot.save(f"plot-{THEME}.png", dpi=400, width=8, height=4.5, units="in", verbose=False)

Part of Basic Parallel Coordinates Plot on anyplot.ai.

Other implementations