<div id="sigma-container"></div>
import Graph from "graphology";
import Sigma from "sigma";
import { DEFAULT_STYLES } from "sigma/types";
nodes: { key: string; label: string; tag: string; cluster: string; x: number; y: number; score: number }[];
edges: [string, string][];
clusters: { key: string; color: string; clusterLabel: string }[];
const response = await fetch("/data/wikipedia.json");
const dataset: Dataset = await response.json();
const clusterColors = Object.fromEntries(dataset.clusters.map((c) => [c.key, c.color]));
const graph = new Graph();
const scoreExtents = { min: Infinity, max: -Infinity };
for (const node of dataset.nodes) {
scoreExtents.min = Math.min(scoreExtents.min, node.score);
scoreExtents.max = Math.max(scoreExtents.max, node.score);
graph.addNode(node.key, {
for (const [source, target] of dataset.edges) {
if (graph.hasNode(source) && graph.hasNode(target) && !graph.hasEdge(source, target)) {
graph.addEdge(source, target);
const renderer = new Sigma(graph, document.getElementById("sigma-container") as HTMLElement, {
hasActiveSubgraph: false,
size: { attribute: "score", min: 10, max: 50, minValue: scoreExtents.min, maxValue: scoreExtents.max },
label: { attribute: "label" },
when: (_attrs, state, graphState) => graphState.hasActiveSubgraph && !state.isActive && !state.isHovered,
then: { color: "#eee", label: "" },
then: { depth: "activeNodes" },
then: { depth: "topNodes" },
{ color: "#ccc", size: 5 },
when: (_attrs, state, graphState) => graphState.hasActiveSubgraph && !state.isActive,
then: { depth: "activeEdges" },
function setActiveSubgraph(activeNodes: Set<string> | null) {
graph.forEachNode((node) => {
renderer.setNodeState(node, { isActive: activeNodes?.has(node) });
graph.forEachEdge((edge) => {
const [source, target] = graph.extremities(edge);
renderer.setEdgeState(edge, { isActive: activeNodes?.has(source) && activeNodes?.has(target) });
renderer.setGraphState({ hasActiveSubgraph: !!activeNodes });
// Trigger a renderer update:
renderer.refresh({ skipIndexation: true });
renderer.on("enterNode", ({ node }) => {
const neighbors = new Set(graph.neighbors(node));
setActiveSubgraph(neighbors);
renderer.on("leaveNode", () => {