运行 ForceAtlas2 来自 Sigma.js 中的设定位置

Running ForceAtlas2 from a set position in Sigma.js

我正在尝试使用 React-Sigma 包装器渲染一个复杂的网络。我知道这个网络的基本结构是许多一级节点和一些非常高的节点。为此,我使用表示近似布局的 x 和 y 坐标对我的图形数据进行了预格式化,其中一级节点聚集在它们所连接的节点周围。然后我想运行从这点开始ForceAtlas2模拟。然而,当我尝试这样做时,模拟似乎只是随机化并将节点的初始位置更改为位于中心,如此 gif 所示:

有什么办法可以阻止这种情况的发生以及运行从初始位置开始模拟吗?我的代码如下:

const App = () => {
    const myGraph = getExampleGraph();
    return (
        <Sigma
            graph={myGraph}
            renderer="webgl"
            settings={{
                clone: false,
                batchEdgesDrawing: true,
            }}
            style={{
                height: "100vh"
            }}
        >
            <ForceAtlas2
                iterationsPerRender={1}
                barnesHutOptimize
                barnesHutTheta={1}
                timeout={50000}
                worker
            />
        </Sigma>
    )
}

获取我描述的随机示例图的代码:

export const getRandomInt = (max: number) => Math.floor(Math.random() * Math.floor(max));

export const getRandomPosition = () => ({
    x: Math.random(),
    y: Math.random()
});

export const randomisePosition = (position) => ({
    x: position.x + (Math.random() - .5)/10,
    y: position.y + (Math.random() - .5)/10
});


export const getExampleGraph = () => {

    const positions: any = {
        "1": getRandomPosition(),
        "2": getRandomPosition(),
        "3": getRandomPosition()
    };
    const highDegNodes = [
        { id: "1", size: 20, label: "1", ...positions["1"]},
        { id: "2", size: 20, label: "2", ...positions["2"] },
        { id: "3", size: 20, label: "3", ...positions["3"] }
    ];
    const nodes = Object.assign([], highDegNodes);
    const edges = [];

    for(let i = 0; i < 50; i += 1) {
        const id = (i + 4) + '';
        const node = { id, size: 1, label: id, x: 0, y: 0 };

        const target = (getRandomInt(3) + 1) + '';
        edges.push({
            id: `${id}:${target}:${i}`,
            source: id,
            target,
        });

        const nodePos = randomisePosition(positions[target]);
        node.x = nodePos.x;
        node.y = nodePos.y;
        nodes.push(node);

        if (Math.random() < .1) {
            const target2 = (getRandomInt(3) + 1) + '';
            edges.push({
                id: `${id}:${target2}:${i}:2`,
                source: id,
                target: target2,
            });
        }
    }

    return {
        nodes,
        edges
    }
};

Sigma.js 中使用的 ForceAtlas2 的实现存在问题。它期望更高的职位规模,并且在规模小于 1 时非常不稳定。

最容易稳定的是你可以将你的仓位乘以100:

const getRandomPosition = () => ({
    x: Math.random()*100,
    y: Math.random()*100
});

const randomisePosition = (position) => ({
    x: position.x + (Math.random() - .5)*10,
    y: position.y + (Math.random() - .5)*10
});

如果您的图形不是太大,您还可以将 slowDown={10} 应用于 forceAtlas 以使其更柔和并删除 batchEdgesDrawing:

        <Sigma
            graph={myGraph}
            renderer="webgl"
            settings={{
                clone: false,
            }}
            style={{
                height: "100vh"
            }}
        >
          <ForceAtlas2
               iterationsPerRender={1}
               barnesHutOptimize
               barnesHutTheta={1}
               slowDown={10}
               timeout={2000}
               worker
          />
        </Sigma>