Skip to content
This is the alpha v4 version website. Looking for the v3 documentation?

Parallel edges and self-loops

Sigma handles two special edge cases: multiple edges between the same pair of nodes (parallel edges), and edges that connect a node to itself (self-loops).

Parallel edges

When multiple edges connect the same pair of nodes, sigma can spread them apart automatically. Sigma provides built-in state flags parallelIndex and parallelCount on edges to support this.

Use the parallelPath style property to choose a curved path for parallel edges, and parallelSpread to control the spacing:

import Sigma from "sigma";
import { extremityArrow, layerPlain, pathCurved, pathLine, pathLoop } from "sigma/rendering";
import { DEFAULT_STYLES } from "sigma/types";
import { getSmallGraph } from "../_data/small-graph";
const container = document.getElementById("sigma-container") as HTMLElement;
const graph = getSmallGraph({ multi: true, type: "mixed" });
// Add parallel edges to showcase the feature:
// Multiple directed edges, same direction (a -> b already exists)
graph.addDirectedEdge("a", "b", { size: 3, color: "#F6903D", head: "arrow" });
graph.addDirectedEdge("a", "b", { size: 3, color: "#FACC14", head: "arrow" });
// Directed edges in both directions (c -> e already exists, add e -> c)
graph.addDirectedEdge("e", "c", { size: 3, color: "#61DDAA", head: "arrow" });
// Undirected parallel edges
graph.addUndirectedEdge("d", "e", { size: 3, color: "#78D3F8" });
graph.addUndirectedEdge("d", "e", { size: 3, color: "#247BA0" });
new Sigma(graph, container, {
primitives: {
edges: {
paths: [pathLine(), pathCurved(), pathLoop()],
extremities: [extremityArrow()],
layers: [layerPlain()],
},
},
styles: {
nodes: {
...DEFAULT_STYLES.nodes,
color: { attribute: "color" },
size: { attribute: "size" },
},
edges: {
...DEFAULT_STYLES.edges,
color: { attribute: "color" },
size: { attribute: "size" },
path: "straight",
selfLoopPath: "loop",
parallelPath: "curved",
head: { attribute: "head" },
},
},
settings: {
itemSizesReference: "positions",
autoRescale: true,
},
});

Self-loops

Edges that connect a node to itself are rendered as loops. The selfLoopPath style property controls their shape:

import Sigma from "sigma";
import { extremityArrow, layerDashed, layerFill, layerPlain, pathLine, pathLoop } from "sigma/rendering";
import { DEFAULT_STYLES } from "sigma/types";
import { getSmallGraph } from "../_data/small-graph";
const container = document.getElementById("sigma-container") as HTMLElement;
const PI = Math.PI;
const graph = getSmallGraph({ multi: true });
// Add self-loops showcasing various features:
graph.addEdge("a", "a", { size: 3, color: "#E8684A", head: "arrow" });
graph.addEdge("d", "d", { size: 2, color: "#9270CA", head: "arrow", loopAngle: (3 * PI) / 2, dashSize: 6 });
graph.addEdge("e", "e", { size: 6, color: "#5B8FF9", loopAngle: PI, loopSpread: (110 * PI) / 180 });
graph.addEdge("f", "f", { size: 2, color: "#9270CA", head: "arrow", loopAngle: 0, loopSpread: (70 * PI) / 180 });
// Add parallel self-loops on a few nodes to showcase automatic angle distribution:
graph.addEdge("b", "b", { size: 3, color: "#61DDAA", head: "arrow", tail: "arrow" });
graph.addEdge("b", "b", { size: 2, color: "#F6903D", head: "arrow", tail: "arrow" });
graph.addEdge("c", "c", { size: 3, color: "#A33DF6", head: "arrow" });
graph.addEdge("c", "c", { size: 2, color: "#61ADDD", head: "arrow" });
graph.addEdge("c", "c", { size: 2, color: "#9270CA", head: "arrow" });
new Sigma(graph, container, {
primitives: {
nodes: {
layers: [layerFill()],
},
edges: {
paths: [pathLine(), pathLoop()],
variables: { dashSize: { type: "number", default: 0 } },
extremities: [extremityArrow()],
layers: [
layerPlain(),
layerDashed({
dashSize: { attribute: "dashSize", default: 0, mode: "pixels" },
gapSize: { value: 6, mode: "pixels" },
gapColor: "#ffffff",
}),
],
},
},
styles: {
nodes: {
...DEFAULT_STYLES.nodes,
color: { attribute: "color" },
size: { attribute: "size" },
},
edges: {
...DEFAULT_STYLES.edges,
color: { attribute: "color" },
size: { attribute: "size" },
path: "straight",
selfLoopPath: "loop",
head: { attribute: "head" },
tail: { attribute: "tail" },
},
},
settings: {
itemSizesReference: "positions",
autoRescale: true,
},
});