SHAP Summary Plot — plotnine

A SHAP (SHapley Additive exPlanations) summary plot displaying the distribution of SHAP values for each feature, ordered by mean absolute SHAP value (importance). Each dot represents a sample, positioned horizontally by its SHAP value and colored by the feature's value (typically low=blue to high=red). This visualization is essential for machine learning interpretability, showing both feature importance and the direction and magnitude of feature effects on model predictions.

SHAP Summary Plot rendered with plotnine

Renders

Python source (plotnine)

""" anyplot.ai
shap-summary: SHAP Summary Plot
Library: plotnine 0.15.4 | Python 3.13.13
Quality: 96/100 | Created: 2026-05-14
"""

import os
import site
import sys


# Add site-packages to the beginning of path to prioritize installed packages
site_packages = next((p for p in site.getsitepackages() if "site-packages" in p), None)
if site_packages:
    sys.path.insert(0, site_packages)

import numpy as np
import pandas as pd
from plotnine import (
    aes,
    element_line,
    element_rect,
    element_text,
    geom_point,
    geom_vline,
    ggplot,
    ggsave,
    labs,
    scale_color_cmap,
    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"

# Generate synthetic SHAP-like data
np.random.seed(42)
n_samples = 250
n_features = 15

# Feature names (simulating model features)
feature_names = [
    "Radius",
    "Texture",
    "Perimeter",
    "Area",
    "Smoothness",
    "Compactness",
    "Concavity",
    "Concave Points",
    "Symmetry",
    "Fractal Dimension",
    "Gray Mean",
    "Gray Std",
    "Radius SE",
    "Texture SE",
    "Perimeter SE",
]

# Generate realistic SHAP values with different distributions per feature
shap_values = np.zeros((n_samples, n_features))
feature_values = np.zeros((n_samples, n_features))

for i in range(n_features):
    # Different distributions for different features
    scale = np.random.uniform(0.3, 1.5)
    center = np.random.uniform(-0.5, 0.5)

    # Generate SHAP values with some features showing positive/negative effects
    shap_values[:, i] = np.random.normal(center, scale, n_samples)

    # Generate normalized feature values (0 to 1) for coloring
    feature_values[:, i] = np.random.uniform(0, 1, n_samples)

# Calculate importance (mean absolute SHAP value) and sort
feature_importance = np.abs(shap_values).mean(axis=0)
sorted_indices = np.argsort(feature_importance)[::-1]

# Create long format dataframe for plotnine
rows = []
for rank, feat_idx in enumerate(sorted_indices):
    feat_name = feature_names[feat_idx]
    shap_vals = shap_values[:, feat_idx]
    feat_vals = feature_values[:, feat_idx]

    for shap_val, feat_val in zip(shap_vals, feat_vals, strict=False):
        rows.append({"feature": feat_name, "shap_value": shap_val, "feature_value": feat_val, "feature_rank": rank})

df = pd.DataFrame(rows)

# Create categorical feature order for Y-axis (sorted by importance)
sorted_feature_names = [feature_names[i] for i in sorted_indices]
df["feature"] = pd.Categorical(df["feature"], categories=sorted_feature_names, ordered=True)

# Plot
plot = (
    ggplot(df, aes(x="shap_value", y="feature", color="feature_value"))
    + geom_point(size=2.5, alpha=0.6)
    + geom_vline(xintercept=0, linetype="solid", color=INK_SOFT, size=0.8, alpha=0.5)
    + scale_color_cmap(cmap_name="BrBG", limits=[0, 1])
    + labs(
        title="shap-summary · plotnine · anyplot.ai",
        x="SHAP Value (impact on prediction)",
        y="Feature",
        color="Feature Value\n(low → high)",
    )
    + theme_minimal()
    + theme(
        figure_size=(16, 9),
        plot_background=element_rect(fill=PAGE_BG, color=PAGE_BG),
        panel_background=element_rect(fill=PAGE_BG),
        panel_grid_major=element_line(color=INK, size=0.3, alpha=0.10),
        panel_grid_minor=element_line(color=INK, size=0.2, alpha=0.05),
        panel_border=element_rect(color=INK_SOFT, fill=None),
        plot_title=element_text(size=24, color=INK, weight="medium"),
        axis_title=element_text(size=20, color=INK),
        axis_text=element_text(size=16, color=INK_SOFT),
        axis_line=element_line(color=INK_SOFT, size=0.5),
        legend_background=element_rect(fill=ELEVATED_BG, color=INK_SOFT),
        legend_text=element_text(size=16, color=INK_SOFT),
        legend_title=element_text(size=16, color=INK),
    )
)

# Save to script directory
script_dir = os.path.dirname(os.path.abspath(__file__))
ggsave(plot, filename=os.path.join(script_dir, f"plot-{THEME}.png"), dpi=300, width=16, height=9)

Part of SHAP Summary Plot on anyplot.ai.

Other implementations