Skip to content

Clustering

Groups related nodes into single aggregate nodes. Group by data field or custom predicate, then expand clusters.

Usage

TypeScript
// Group by a data field
graph.cluster({ groupBy: 'department' });

// Group by a custom function
graph.cluster({
  groupBy: (node) => {
    if (node.data.revenue > 1000000) return 'high-value';
    if (node.data.revenue > 100000) return 'medium-value';
    return 'low-value';
  },
});

// Restore original graph
graph.uncluster();

Full Options

TypeScript
graph.cluster({
  groupBy: 'data.type',
  style: { shape: 'circle', fill: '#3b82f6', radius: 40, stroke: '#60a5fa' },
  label: (groupName, nodes) => `${groupName} (${nodes.length})`,
  groupStyle: {
    'engineering': { fill: '#3b82f6' },
    'design':      { fill: '#8b5cf6' },
    'marketing':   { fill: '#10b981' },
  },
});
OptionTypeDescription
groupBystring | (node) => stringField name (dot-path) or function returning group key.
styleNodeStyleDefault style for all cluster nodes.
label(groupName, nodes) => stringLabel generator for cluster nodes.
groupStyleRecord<string, NodeStyle>Per-group style overrides.

Cluster Node Data

Each cluster node has aggregate info on data:

PropertyTypeDescription
data._clusterbooleanAlways true.
data._groupNamestringGroup key.
data._membersNode[]Original nodes in cluster.
data._memberCountnumberNode count.

Cluster Edges

Edges between groups are aggregated into cluster edges with data._clusterEdge, data._edgeCount, and group info. Width scales with edge count.

Complete Example

TypeScript
import { create } from '@topokit/renderer-canvas';

const app = create(container, {
  nodes: employees,
  edges: collaborations,
  layout: 'force',
  theme: 'dark',
});

const graph = app.graph;

graph.cluster({
  groupBy: 'department',
  label: (dept, nodes) => `${dept} (${nodes.length} people)`,
  groupStyle: {
    'Engineering': { fill: '#3b82f6', radius: 35 },
    'Design':      { fill: '#8b5cf6', radius: 30 },
    'Marketing':   { fill: '#f59e0b', radius: 28 },
    'Sales':       { fill: '#10b981', radius: 32 },
  },
});

// Double-click cluster to uncluster and highlight that group
graph.on('node:dblclick', ({ node }) => {
  if (node.data._cluster) {
    graph.uncluster();
    graph.highlightByPredicate(
      (n) => n.data.department === node.data._groupName
    );
  }
});

Next Steps

  • Data Mapping -- import JSON and auto-style by group
  • Filtering -- filter before or after clustering
  • Legend -- auto-generate legend from clusters