Node Aggregation
The node aggregation algorithm repeatedly clusters the nodes of a given graph and creates a hierarchical structure of clusters. It achieves this by smartly selecting appropriate clustering algorithms and applying them repeatedly. The result may for example be used to collapse regions to simplify interactively browsing large graphs. Refer to the LargeGraphAggregation demo on how to integrate the aggregation result for such a use case.
The result of a node aggregation algorithm is a tree of elements of type NodeAggregate. Each NodeAggregate consists of a collection of child aggregates, which together with the NodeAggregate itself represent a cluster of graph nodes. The corresponding graph node of an aggregate can be accessed by each aggregate’s node property. And vice versa, the NodeAggregationResult provides a mapping from nodes to their respective aggregate exposed by the aggregateMap. Also, the NodeAggregationResult provides the root of the resulting tree.
An NodeAggregate together with its child nodes represents a cluster. In the example above the NodeAggregate containing the blue node together with its child aggregates forms a cluster which contains the blue, magenta, and orange node.
Calculating a Node Aggregation shows how to structurally aggregate the nodes of a graph.
// prepare the node aggregation algorithm
const algorithm = new NodeAggregation({
// determine substructures according to the graph structure, not the geometry/coordinates
aggregation: NodeAggregationPolicy.STRUCTURAL
})
// run the algorithm
const result = algorithm.run(graph)
Note that some aggregates are purely virtual tree nodes that do not contain a graph node. The leaves of the aggregate tree always contain a graph node. nodesOnlyOnLeaves can be set to prevent non-leaf aggregates from containing a node.
The aggregation algorithm can be configured in a number of ways. The preferred resulting cluster sizes can be set by minimumClusterSize and maximumClusterSize. However, these are hints, and the algorithm does not guarantee that the resulting clusters strictly observe these values.
By setting the aggregation policy, the algorithm can be configured to operate either on the structural properties of the given graph, such that groups of nodes that are highly interconnected are likely placed into the same cluster. Or alternatively, to take the positions of nodes into account, such that nodes that are geometrically close to each other are likely clustered together.
Node weights can be set to nudge the algorithm into placing certain nodes closer to the root of the aggregation hierarchy. These weights can be set via a mapper such as shown in Setting node weights. For more information about mapping items see Associating Data with Graph Elements. If specific nodes are to be placed at the top of the hierarchy, they can directly be set as top-level nodes.
// creates a mapping that sets the weight of a node to the length of it's label
// placing nodes with long text higher up the hierarchy
nodeAggregation.nodeWeights.delegate = (node) => node.labels.first().text.length
It is also possible to exclude certain nodes from being clustered together. This can be controlled by associating each node with an arbitrary type object via nodeTypes and setting a NodeAggregationNodeTypeHandlingPolicy to nodeTypeHandling. Nodes with different types are then prevented from being clustered together.
// creates a mapping that associates a node to it's color
nodeAggregation.nodeTypes.delegate = (node) => node.tag.color
// sets how the algorithm handles the types
nodeAggregation.nodeTypeHandling = NodeAggregationNodeTypeHandlingPolicy.SEPARATE_AT_LEAVES