{"spec_id":"scatter-embedding","library":"highcharts","language":"javascript","code":"// anyplot.ai\n// scatter-embedding: t-SNE and UMAP Embedding Visualization\n// Library: highcharts 12.6.0 | JavaScript 22.23.1\n// Quality: 88/100 | Created: 2026-08-11\n//# anyplot-orientation: landscape\n// anyplot.ai\n// scatter-embedding: t-SNE and UMAP Embedding Visualization\n// Library: Highcharts 12.6.0 | Node 22\n// License: Highcharts — commercial license, free for non-commercial use (highcharts.com/license)\n// Quality: pending | Created: 2026-08-11\n\nconst t = window.ANYPLOT_TOKENS;\n\n// --- Data: UMAP projection of customer-support ticket embeddings -----------\n// Deterministic LCG so the layout is reproducible across renders.\nlet seed = 42;\nfunction nextRandom() {\n  seed = (seed * 1664525 + 1013904223) % 4294967296;\n  return seed / 4294967296;\n}\nfunction gaussian() {\n  const u1 = Math.max(nextRandom(), 1e-9);\n  const u2 = nextRandom();\n  return Math.sqrt(-2 * Math.log(u1)) * Math.cos(2 * Math.PI * u2);\n}\n\nconst clusters = [\n  { name: \"Billing\", center: [-6, 4], spread: 1.1, symbol: \"circle\" },\n  { name: \"Shipping\", center: [5, 5], spread: 1.3, symbol: \"diamond\" },\n  { name: \"Product Quality\", center: [0, -1], spread: 1.6, symbol: \"triangle\" },\n  { name: \"Account Access\", center: [-6.5, -4.5], spread: 1.0, symbol: \"square\" },\n  { name: \"Returns\", center: [6, -4.5], spread: 1.2, symbol: \"triangle-down\" },\n];\n\nconst pointsPerCluster = 120; // 600 points total — within the spec's 500-5000 range\n\nconst clusterSeries = clusters.map((cluster) => {\n  const data = [];\n  for (let i = 0; i < pointsPerCluster; i++) {\n    data.push([\n      cluster.center[0] + gaussian() * cluster.spread,\n      cluster.center[1] + gaussian() * cluster.spread,\n    ]);\n  }\n  return {\n    type: \"scatter\",\n    name: cluster.name,\n    data,\n    opacity: 0.6,\n    marker: { radius: 6, symbol: cluster.symbol },\n  };\n});\n\nconst centroidSeries = {\n  type: \"scatter\",\n  name: \"Cluster centroids\",\n  showInLegend: false,\n  enableMouseTracking: false,\n  marker: { enabled: false },\n  dataLabels: {\n    enabled: true,\n    format: \"{point.name}\",\n    verticalAlign: \"bottom\",\n    y: -16,\n    style: {\n      color: t.ink,\n      fontSize: \"14px\",\n      fontWeight: \"600\",\n      textOutline: `4px ${t.pageBg}`,\n    },\n  },\n  data: clusters.map((cluster) => ({\n    x: cluster.center[0],\n    y: cluster.center[1],\n    name: cluster.name,\n  })),\n};\n\n// --- Chart -------------------------------------------------------------\nHighcharts.chart(\"container\", {\n  chart: {\n    type: \"scatter\",\n    backgroundColor: \"transparent\",\n    animation: false,\n    zoomType: \"xy\",\n    style: { fontFamily: \"inherit\" },\n    resetZoomButton: {\n      theme: { fill: t.elevatedBg, stroke: t.grid, style: { color: t.ink } },\n    },\n  },\n  credits: { enabled: false },\n  colors: t.palette,\n  title: {\n    text: \"scatter-embedding · javascript · highcharts · anyplot.ai\",\n    style: { color: t.ink, fontSize: \"22px\", fontWeight: \"600\" },\n  },\n  subtitle: {\n    text: \"UMAP projection (n_neighbors=15) of support-ticket embeddings, colored by topic cluster\",\n    style: { color: t.inkSoft, fontSize: \"14px\" },\n  },\n  xAxis: {\n    title: { text: \"UMAP Dimension 1\", style: { color: t.inkSoft, fontSize: \"16px\" } },\n    labels: { enabled: false },\n    tickLength: 0,\n    lineColor: t.inkSoft,\n    gridLineWidth: 1,\n    gridLineColor: t.grid,\n  },\n  yAxis: {\n    title: { text: \"UMAP Dimension 2\", style: { color: t.inkSoft, fontSize: \"16px\" } },\n    labels: { enabled: false },\n    tickLength: 0,\n    lineColor: t.inkSoft,\n    gridLineWidth: 1,\n    gridLineColor: t.grid,\n  },\n  legend: {\n    itemStyle: { color: t.inkSoft, fontSize: \"14px\" },\n    itemHoverStyle: { color: t.ink },\n  },\n  tooltip: {\n    backgroundColor: t.elevatedBg,\n    borderColor: t.grid,\n    style: { color: t.ink, fontSize: \"13px\" },\n    headerFormat: '<span style=\"font-weight:600\">{series.name}</span><br/>',\n    pointFormat: \"UMAP Dim 1: {point.x:.2f}  ·  UMAP Dim 2: {point.y:.2f}\",\n  },\n  plotOptions: {\n    series: { animation: false },\n    scatter: { states: { hover: { enabled: false } } },\n  },\n  series: [...clusterSeries, centroidSeries],\n});\n"}