EdgeBundling
Overview
Edge bundling is a graph visualization technique used to reduce visual clutter in complex network graphs and to reveal high-level patterns and structures in the graph. Its purpose is to bundle adjacent edges together.
The edge bundling plugin provided in G6 is based on the implementation of the FEDB (Force-Directed Edge Bundling for Graph Visualization) paper: modeling edges as flexible springs that can attract each other and bundling them through a self-organizing process.
Use Cases
The edge bundling plugin is mainly suitable for the following scenarios:
- Reducing visual clutter in complex network graphs
- Revealing high-level patterns and structures in the graph
- Improving the readability and aesthetics of large-scale graph data
Basic Usage
Below is a simple example of initializing the EdgeBundling plugin:
const graph = new Graph({
plugins: [
{
type: 'edge-bundling',
bundleThreshold: 0.6,
cycles: 6,
divisions: 3,
divRate: 2,
iterations: 90,
iterRate: 2 / 3,
K: 0.1,
lambda: 0.1,
},
],
});
Configuration Options
| Property | Description | Type | Default Value | Required |
|---|---|---|---|---|
| type | Plugin type, used to identify the plugin as an edge bundling plugin | string | edge-bundling |
✓ |
| key | Unique identifier for the plugin, can be used to get the plugin instance or update plugin options | string | - | |
| bundleThreshold | Edge compatibility threshold, determines which edges should be bundled together, the larger the value, the fewer edges are bundled, example | number | 0.6 | |
| cycles | Number of simulation cycles, controls the number of execution rounds of the edge bundling simulation | number | 6 | |
| divisions | Initial number of cut points, in subsequent cycles, the number of cut points will gradually increase according to divRate, affecting the degree of edge subdivision | number | 1 | |
| divRate | Growth rate of cut points, determines the growth rate of cut points in each cycle | number | 2 | |
| iterations | Specifies the number of iterations executed in the first cycle, in subsequent cycles, the number of iterations will gradually decrease according to iterRate, affecting the accuracy of the simulation | number | 90 | |
| iterRate | Iteration decrement rate, controls the reduction ratio of iterations in each cycle | number | 2/3 | |
| K | Edge strength, affects the attraction and repulsion between edges, example | number | 0.1 | |
| lambda | Initial step size, in subsequent cycles, the step size will double increment, affecting the magnitude of node movement during edge bundling | number | 0.1 |
bundleThreshold
Edge compatibility threshold, determines which edges should be bundled together. The larger the value, the fewer edges are bundled, and vice versa.
- A lower bundleThreshold value (e.g., 0.4) will cause more edges to be bundled together, forming a more pronounced bundling effect.
const graph = new Graph({
plugins: [
{
type: 'edge-bundling',
bundleThreshold: 0.4, // Lower edge compatibility threshold
},
],
});
The effect is as follows:
- A higher bundleThreshold value (e.g., 0.8) will cause fewer edges to be bundled together, maintaining more independent edges.
const graph = new Graph({
plugins: [
{
type: 'edge-bundling',
bundleThreshold: 0.8, // Higher edge compatibility threshold
},
],
});
The effect is as follows:
K
Edge strength, affects the attraction and repulsion between edges. A higher K value will make the attraction between edges stronger, resulting in a tighter bundling effect.
- A lower K value (e.g., 0.05) will make the attraction between edges weaker, resulting in a weaker bundling effect.
const graph = new Graph({
plugins: [
{
type: 'edge-bundling',
K: 0.05, // Lower edge strength
},
],
});
The effect is as follows:
- A higher K value (e.g., 0.2) will make the attraction between edges stronger, resulting in a more pronounced bundling effect.
const graph = new Graph({
plugins: [
{
type: 'edge-bundling',
K: 0.2, // Higher edge strength
},
],
});
The effect is as follows:
Code Examples
Basic Edge Bundling
The simplest way is to use the preset configuration directly:
const graph = new Graph({
// Other configurations...
plugins: ['edge-bundling'],
});
Custom Styles
You can customize the parameters of edge bundling as needed:
const graph = new Graph({
// Other configurations...
plugins: [
{
type: 'edge-bundling',
bundleThreshold: 0.8, // Higher edge compatibility threshold
cycles: 8, // More simulation cycles
K: 0.2, // Stronger edge strength
},
],
});
Dynamic Update of Edge Bundling
Use the key identifier to dynamically update edge bundling properties at runtime:
// Initial configuration
const graph = new Graph({
// Other configurations...
plugins: [
{
type: 'edge-bundling',
key: 'my-edge-bundling',
bundleThreshold: 0.6,
},
],
});
// Subsequent dynamic update
graph.updatePlugin({
key: 'my-edge-bundling',
bundleThreshold: 0.8, // Update edge compatibility threshold
cycles: 10, // Update number of simulation cycles
});
Practical Examples
import { Graph } from '@antv/g6';
fetch('https://assets.antv.antgroup.com/g6/circular.json')
.then((res) => res.json())
.then((data) => {
const graph = new Graph({
container: 'container',
autoFit: 'view',
data,
layout: {
type: 'circular',
},
node: { style: { size: 20 } },
behaviors: ['drag-canvas', 'drag-element'],
plugins: [
{
key: 'edge-bundling',
type: 'edge-bundling',
bundleThreshold: 0.1,
},
],
});
graph.render();
});
import { Graph } from '@antv/g6';
import GUI from 'lil-gui';
export function addPanel(renderPanel: (gui: GUI) => void) {
const gui = new GUI({ container: document.body });
gui.title('Control');
Object.assign(gui.domElement.style, { position: 'absolute', top: '0', right: '0', zIndex: '10' });
renderPanel(gui);
addEventListener('pagehide', () => gui.destroy(), { once: true });
}
export async function createGraph(
options: ConstructorParameters<typeof Graph>[0],
size: { width?: number; height?: number } = {},
renderPanel?: (gui: GUI, graph: Graph) => void,
) {
const container = document.createElement('div');
Object.assign(container.style, {
width: '100%',
maxWidth: `${size.width || 600}px`,
height: `${size.height || 400}px`,
});
document.getElementById('container')!.append(container);
const graph = new Graph({ ...size, ...options, width: container.clientWidth, container, autoResize: true });
addEventListener('pagehide', () => graph.destroy(), { once: true });
await graph.render();
if (renderPanel) addPanel((gui) => renderPanel(gui, graph));
return container;
}