{"spec_id":"shap-summary","library":"seaborn","language":"python","code":"\"\"\" anyplot.ai\nshap-summary: SHAP Summary Plot\nLibrary: seaborn 0.13.2 | Python 3.13.13\nQuality: 93/100 | Updated: 2026-05-14\n\"\"\"\n\nimport os\nimport sys\n\n\nsys.path.insert(0, \"/home/runner/work/anyplot/anyplot/.venv/lib/python3.13/site-packages\")\n\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport pandas as pd\nimport seaborn as sns\nfrom matplotlib.colors import Normalize\nfrom sklearn.datasets import make_classification\nfrom sklearn.ensemble import GradientBoostingClassifier\n\n\n# Theme tokens\nTHEME = os.getenv(\"ANYPLOT_THEME\", \"light\")\nPAGE_BG = \"#FAF8F1\" if THEME == \"light\" else \"#1A1A17\"\nELEVATED_BG = \"#FFFDF6\" if THEME == \"light\" else \"#242420\"\nINK = \"#1A1A17\" if THEME == \"light\" else \"#F0EFE8\"\nINK_SOFT = \"#4A4A44\" if THEME == \"light\" else \"#B8B7B0\"\n\n# Data - Train a model and compute SHAP-like values for credit approval\nnp.random.seed(42)\nX, y = make_classification(\n    n_samples=300, n_features=12, n_informative=10, n_redundant=2, n_classes=2, random_state=42, class_sep=1.5\n)\n\nfeature_names = [\n    \"Annual Income\",\n    \"Credit Score\",\n    \"Employment Years\",\n    \"Debt Ratio\",\n    \"Savings Balance\",\n    \"Age\",\n    \"Loan Amount\",\n    \"Payment History\",\n    \"Number of Accounts\",\n    \"Previous Defaults\",\n    \"Revolving Credit\",\n    \"Inquiries\",\n]\n\n# Train a gradient boosting model\nmodel = GradientBoostingClassifier(n_estimators=100, max_depth=4, random_state=42)\nmodel.fit(X, y)\n\n# Compute approximate SHAP values using tree-based contribution approach\nn_samples = 200\nsample_indices = np.random.choice(len(X), n_samples, replace=False)\nX_sample = X[sample_indices]\n\n# Calculate feature contributions\nbase_pred = model.predict_proba(X_sample)[:, 1]\nbaseline = base_pred.mean()\nshap_values = np.zeros((n_samples, X_sample.shape[1]))\n\nfor i in range(X_sample.shape[1]):\n    X_low = X_sample.copy()\n    X_high = X_sample.copy()\n    X_low[:, i] = np.percentile(X_sample[:, i], 10)\n    X_high[:, i] = np.percentile(X_sample[:, i], 90)\n    pred_low = model.predict_proba(X_low)[:, 1]\n    pred_high = model.predict_proba(X_high)[:, 1]\n    feat_normalized = (X_sample[:, i] - X_sample[:, i].min()) / (X_sample[:, i].max() - X_sample[:, i].min() + 1e-8)\n    shap_values[:, i] = (pred_high - pred_low) * (feat_normalized - 0.5) * 2\n\n# Normalize feature values for coloring (0 to 1 scale)\nfeature_values_norm = (X_sample - X_sample.min(axis=0)) / (X_sample.max(axis=0) - X_sample.min(axis=0) + 1e-8)\n\n# Sort features by mean absolute SHAP value\nmean_abs_shap = np.abs(shap_values).mean(axis=0)\nsorted_indices = np.argsort(mean_abs_shap)[::-1][:10]  # Top 10 features\n\n# Prepare data for seaborn stripplot\nplot_data = []\nfor rank, feat_idx in enumerate(sorted_indices):\n    for sample in range(n_samples):\n        plot_data.append(\n            {\n                \"Feature\": feature_names[feat_idx],\n                \"SHAP Value\": shap_values[sample, feat_idx],\n                \"Feature Value\": feature_values_norm[sample, feat_idx],\n                \"Rank\": rank,\n            }\n        )\n\ndf = pd.DataFrame(plot_data)\n\n# Create ordered category for proper feature ordering\nordered_features = [feature_names[i] for i in sorted_indices]\ndf[\"Feature\"] = pd.Categorical(df[\"Feature\"], categories=ordered_features, ordered=True)\n\n# Set theme\nsns.set_theme(\n    style=\"ticks\",\n    rc={\n        \"figure.facecolor\": PAGE_BG,\n        \"axes.facecolor\": PAGE_BG,\n        \"axes.edgecolor\": INK_SOFT,\n        \"axes.labelcolor\": INK,\n        \"text.color\": INK,\n        \"xtick.color\": INK_SOFT,\n        \"ytick.color\": INK_SOFT,\n        \"grid.color\": INK,\n        \"grid.alpha\": 0.10,\n    },\n)\n\n# Create plot\nfig, ax = plt.subplots(figsize=(16, 9), facecolor=PAGE_BG)\nax.set_facecolor(PAGE_BG)\n\n# Use seaborn stripplot for the main visualization\nsns.stripplot(\n    data=df,\n    x=\"SHAP Value\",\n    y=\"Feature\",\n    hue=\"Feature Value\",\n    palette=\"BrBG\",\n    size=11,\n    alpha=0.7,\n    jitter=0.3,\n    legend=False,\n    ax=ax,\n)\n\n# Add vertical line at x=0\nax.axvline(x=0, color=INK_SOFT, linestyle=\"-\", linewidth=2, alpha=0.6)\n\n# Styling\nax.set_xlabel(\"SHAP Value (Impact on Approval)\", fontsize=20, color=INK)\nax.set_ylabel(\"Feature\", fontsize=20, color=INK)\nax.set_title(\"shap-summary · seaborn · anyplot.ai\", fontsize=24, color=INK, pad=20)\nax.tick_params(axis=\"both\", labelsize=16, colors=INK_SOFT)\n\n# Subtle grid on x-axis\nax.grid(True, axis=\"x\", alpha=0.15, linestyle=\"-\", linewidth=0.8)\n\n# Add colorbar for feature values\nsm = plt.cm.ScalarMappable(cmap=\"BrBG\", norm=Normalize(vmin=0, vmax=1))\nsm.set_array([])\ncbar = plt.colorbar(sm, ax=ax, pad=0.02)\ncbar.set_label(\"Feature Value (Low to High)\", fontsize=16, rotation=270, labelpad=20, color=INK)\ncbar.ax.tick_params(labelsize=14, colors=INK_SOFT)\n\n# Remove spines\nsns.despine(left=True, ax=ax)\n\nplt.tight_layout()\nplt.savefig(f\"plot-{THEME}.png\", dpi=300, bbox_inches=\"tight\", facecolor=PAGE_BG)\n"}