Skip to main content

Load a graph

Graph property on SigmaContainer

Component SigmaContainer can take a graph property which is either a graph instance or a graph constructor.

So you can use it to load your graph.

Loading a graph via the graph property
import { FC, CSSProperties } from "react";
import { MultiDirectedGraph } from "graphology";

import { SigmaContainer } from "@react-sigma/core";
import "@react-sigma/core/lib/react-sigma.min.css";

export const LoadGraphWithProp: FC<{ style: CSSProperties }> = ({ style }) => {
// Create the graph
const graph = new MultiDirectedGraph();
graph.addNode("A", { x: 0, y: 0, label: "Node A", size: 10 });
graph.addNode("B", { x: 1, y: 1, label: "Node B", size: 10 });
graph.addEdgeWithKey("rel1", "A", "B", { label: "REL_1" });

return <SigmaContainer style={style} graph={graph} settings={{ allowInvalidContainer: true }}></SigmaContainer>;
};

By using useLoadGraph

In a children component of SigmaContainer, you can use the hook useLoadGraph.

This hook is just returns a function that takes a graphology instance, and load it in Sigma.

Loading a graph with useLoadGraph hook
import { FC, useEffect, CSSProperties } from "react";
import { MultiDirectedGraph } from "graphology";

import { SigmaContainer, useLoadGraph } from "@react-sigma/core";
import "@react-sigma/core/lib/react-sigma.min.css";

const MyGraph: FC = () => {
const loadGraph = useLoadGraph();

useEffect(() => {
// Create the graph
const graph = new MultiDirectedGraph();
graph.addNode("A", { x: 0, y: 0, label: "Node A", size: 10 });
graph.addNode("B", { x: 1, y: 1, label: "Node B", size: 10 });
graph.addEdgeWithKey("rel1", "A", "B", { label: "REL_1" });
loadGraph(graph);
}, [loadGraph]);

return null;
};

export const LoadGraphWithHook: FC<{ style?: CSSProperties }> = ({ style }) => {
return (
<SigmaContainer style={style}>
<MyGraph />
</SigmaContainer>
);
};

Per default, when the SigmaContainer is mounted, the library create a default graphology graph (see https://graphology.github.io/instantiation.html). But you can define the type of graph that react-sigma will create by passing the constructor you want to use.

This step is mandatory if you want to use a multi graph (ie. parallel edges).

Defining the graph constructor
import { FC, useEffect, useMemo, CSSProperties } from "react";
import { MultiDirectedGraph as MultiGraphConstructor } from "graphology";
import EdgeCurveProgram, { DEFAULT_EDGE_CURVATURE, indexParallelEdgesIndex } from "@sigma/edge-curve";
import { EdgeArrowProgram } from "sigma/rendering";

import { SigmaContainer, useLoadGraph } from "@react-sigma/core";
import "@react-sigma/core/lib/react-sigma.min.css";

import { useRandom } from "./common/useRandom";

interface NodeType {
x: number;
y: number;
label: string;
size: number;
color: string;
}
interface EdgeType {
type?: string;
label?: string;
size?: number;
curvature?: number;
parallelIndex?: number;
parallelMaxIndex?: number;
}

const MyGraph: React.FC = () => {
const { faker, randomColor } = useRandom();
const loadGraph = useLoadGraph<NodeType, EdgeType>();

useEffect(() => {
// Create the graph
const graph = new MultiGraphConstructor<NodeType, EdgeType>();

graph.addNode("a", {
x: 0,
y: 0,
size: faker.number.int({ min: 4, max: 20 }),
color: randomColor(),
label: faker.person.fullName(),
});
graph.addNode("b", {
x: 1,
y: -1,
size: faker.number.int({ min: 4, max: 20 }),
color: randomColor(),
label: faker.person.fullName(),
});
graph.addNode("c", {
x: 3,
y: -2,
size: faker.number.int({ min: 4, max: 20 }),
color: randomColor(),
label: faker.person.fullName(),
});
graph.addNode("d", {
x: 1,
y: -3,
size: faker.number.int({ min: 4, max: 20 }),
color: randomColor(),
label: faker.person.fullName(),
});
graph.addNode("e", {
x: 3,
y: -4,
size: faker.number.int({ min: 4, max: 20 }),
color: randomColor(),
label: faker.person.fullName(),
});
graph.addNode("f", {
x: 4,
y: -5,
size: faker.number.int({ min: 4, max: 20 }),
color: randomColor(),
label: faker.person.fullName(),
});

graph.addEdge("a", "b", { label: faker.date.anytime().toISOString(), size: faker.number.int({ min: 1, max: 5 }) });
graph.addEdge("b", "c", { label: faker.date.anytime().toISOString(), size: faker.number.int({ min: 1, max: 5 }) });
graph.addEdge("b", "d", { label: faker.date.anytime().toISOString(), size: faker.number.int({ min: 1, max: 5 }) });
graph.addEdge("c", "b", { label: faker.date.anytime().toISOString(), size: faker.number.int({ min: 1, max: 5 }) });
graph.addEdge("c", "e", { label: faker.date.anytime().toISOString(), size: faker.number.int({ min: 1, max: 5 }) });
graph.addEdge("d", "c", { label: faker.date.anytime().toISOString(), size: faker.number.int({ min: 1, max: 5 }) });
graph.addEdge("d", "e", { label: faker.date.anytime().toISOString(), size: faker.number.int({ min: 1, max: 5 }) });
graph.addEdge("d", "e", { label: faker.date.anytime().toISOString(), size: faker.number.int({ min: 1, max: 5 }) });
graph.addEdge("d", "e", { label: faker.date.anytime().toISOString(), size: faker.number.int({ min: 1, max: 5 }) });
graph.addEdge("d", "e", { label: faker.date.anytime().toISOString(), size: faker.number.int({ min: 1, max: 5 }) });
graph.addEdge("e", "d", { label: faker.date.anytime().toISOString(), size: faker.number.int({ min: 1, max: 5 }) });
graph.addEdge("e", "f", { label: faker.date.anytime().toISOString(), size: faker.number.int({ min: 1, max: 5 }) });
graph.addEdge("f", "e", { label: faker.date.anytime().toISOString(), size: faker.number.int({ min: 1, max: 5 }) });
graph.addEdge("f", "e", { label: faker.date.anytime().toISOString(), size: faker.number.int({ min: 1, max: 5 }) });

// Use dedicated helper to identify parallel edges:
indexParallelEdgesIndex(graph, { edgeIndexAttribute: "parallelIndex", edgeMaxIndexAttribute: "parallelMaxIndex" });

// Adapt types and curvature of parallel edges for rendering:
graph.forEachEdge((edge, { parallelIndex, parallelMaxIndex }) => {
if (typeof parallelIndex === "number") {
graph.mergeEdgeAttributes(edge, {
type: "curved",
curvature: DEFAULT_EDGE_CURVATURE + (3 * DEFAULT_EDGE_CURVATURE * parallelIndex) / (parallelMaxIndex || 1),
});
} else {
graph.setEdgeAttribute(edge, "type", "straight");
}
});

// load the graph in sigma
loadGraph(graph);
}, [loadGraph, faker, randomColor]);

return null;
};

export const MultiDirectedGraph: FC<{ style?: CSSProperties }> = ({ style }) => {
// Sigma settings
const settings = useMemo(
() => ({
allowInvalidContainer: true,
renderEdgeLabels: true,
defaultEdgeType: "straight",
edgeProgramClasses: {
straight: EdgeArrowProgram,
curved: EdgeCurveProgram,
},
}),
[],
);

return (
<SigmaContainer style={style} graph={MultiGraphConstructor<NodeType, EdgeType>} settings={settings}>
<MyGraph />
</SigmaContainer>
);
};