{"spec_id":"scatter-embedding","library":"seaborn","language":"python","code":"\"\"\" anyplot.ai\nscatter-embedding: t-SNE and UMAP Embedding Visualization\nLibrary: seaborn 0.13.2 | Python 3.13.14\nQuality: 89/100 | Updated: 2026-08-11\n\"\"\"\n\nimport os\n\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport pandas as pd\nimport seaborn as sns\nfrom sklearn.datasets import make_blobs\nfrom sklearn.manifold import TSNE\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\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        \"legend.facecolor\": ELEVATED_BG,\n        \"legend.edgecolor\": INK_SOFT,\n    },\n)\n\n# Data — synthetic customer behavioral feature vectors (purchase frequency, order\n# value, session depth, email engagement, support load, tenure, ...), reduced to\n# 2D via t-SNE to surface latent segment structure, mirroring a clustering-QC workflow.\nnp.random.seed(42)\nsegment_names = [\n    \"Power Users\",\n    \"Loyal Subscribers\",\n    \"Occasional Buyers\",\n    \"New Signups\",\n    \"Cart Abandoners\",\n    \"Churn Risk\",\n]\nsegment_colors = {\n    \"Power Users\": \"#009E73\",\n    \"Loyal Subscribers\": \"#C475FD\",\n    \"Occasional Buyers\": \"#4467A3\",\n    \"New Signups\": \"#BD8233\",\n    \"Cart Abandoners\": \"#2ABCCD\",\n    \"Churn Risk\": \"#AE3030\",\n}\nn_segments = len(segment_names)\n\nX, y = make_blobs(n_samples=1500, n_features=32, centers=n_segments, cluster_std=8.0, random_state=42)\n\ntsne = TSNE(n_components=2, perplexity=30, random_state=42, max_iter=1000)\nX_embedded = tsne.fit_transform(X)\n\ndf = pd.DataFrame({\"tsne_1\": X_embedded[:, 0], \"tsne_2\": X_embedded[:, 1], \"segment\": [segment_names[i] for i in y]})\n\n# Plot\nfig, ax = plt.subplots(figsize=(8, 4.5), dpi=400, facecolor=PAGE_BG)\nax.set_facecolor(PAGE_BG)\n\nsns.scatterplot(\n    data=df,\n    x=\"tsne_1\",\n    y=\"tsne_2\",\n    hue=\"segment\",\n    hue_order=segment_names,\n    palette=segment_colors,\n    alpha=0.5,\n    s=45,\n    edgecolors=PAGE_BG,\n    linewidth=0.3,\n    ax=ax,\n)\n\n# Pad the data range so centroid labels near the edges (e.g. the rightmost\n# cluster) never reach the legend placed just outside the axes, and the\n# leftmost cluster's label clears the left spine\nax.margins(x=0.20, y=0.12)\n\n# Annotate segment centroids\nfor name in segment_names:\n    mask = df[\"segment\"] == name\n    cx = df.loc[mask, \"tsne_1\"].mean()\n    cy = df.loc[mask, \"tsne_2\"].mean()\n    ax.text(\n        cx,\n        cy,\n        name,\n        fontsize=10,\n        fontweight=\"semibold\",\n        color=segment_colors[name],\n        ha=\"center\",\n        va=\"center\",\n        bbox={\n            \"boxstyle\": \"round,pad=0.3\",\n            \"facecolor\": ELEVATED_BG,\n            \"edgecolor\": segment_colors[name],\n            \"alpha\": 0.9,\n            \"linewidth\": 1.2,\n        },\n    )\n\n# Axes — no tick labels (embedding coordinates are not interpretable)\nax.set_xlabel(\"t-SNE 1\", fontsize=11, color=INK)\nax.set_ylabel(\"t-SNE 2\", fontsize=11, color=INK)\nax.set_xticks([])\nax.set_yticks([])\n\n# Spines\nax.spines[\"top\"].set_visible(False)\nax.spines[\"right\"].set_visible(False)\nax.spines[\"left\"].set_color(INK_SOFT)\nax.spines[\"bottom\"].set_color(INK_SOFT)\n\n# Legend — placed outside the axes so it never overlaps a cluster (t-SNE\n# layout is data-dependent and any in-plot corner risks landing on a cluster)\nsns.move_legend(ax, \"center left\", bbox_to_anchor=(1.02, 0.5))\nlegend = ax.get_legend()\nlegend.set_title(\"Segment\", prop={\"size\": 11, \"weight\": \"medium\"})\nlegend.get_title().set_color(INK)\nfor text in legend.get_texts():\n    text.set_fontsize(10)\n    text.set_color(INK)\nlegend.get_frame().set_facecolor(ELEVATED_BG)\nlegend.get_frame().set_edgecolor(INK_SOFT)\n\n# Title block\nfig.suptitle(\"scatter-embedding · python · seaborn · anyplot.ai\", fontsize=13, fontweight=\"medium\", color=INK, y=0.98)\nfig.text(\n    0.5,\n    0.92,\n    \"t-SNE (perplexity=30)  ·  1500 customers  ·  6 behavioral segments  ·  clustering QC\",\n    fontsize=10,\n    ha=\"center\",\n    va=\"top\",\n    color=INK_SOFT,\n)\n\nplt.tight_layout(rect=[0, 0, 0.97, 0.90])\nplt.savefig(f\"plot-{THEME}.png\", dpi=400, facecolor=PAGE_BG)\n"}