gpt4 book ai didi

javascript - 将 d3.layout.force v3 更新到 d3.forceSimulation v7

转载 作者:行者123 更新时间:2023-12-05 00:38:44 34 4
gpt4 key购买 nike

我正在尝试将使用 d3js 版本 3 编写的强制导向图更新到 d3js 版本 7。
以下代码片段是使用 d3js v3 的工作实现:

var svg = d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height");

graph = {
nodes: [],
links: [],
}

var simulation = d3.layout.force()
.size([width, height])
.nodes(graph.nodes)
.links(graph.links)
.on("tick", function() {
svg.selectAll('.link')
.attr("x1", function (d) { return d.source.x })
.attr("y1", function (d) { return d.source.y })
.attr("x2", function (d) { return d.target.x })
.attr("y2", function (d) { return d.target.y })

svg.selectAll('.node')
.attr("cx", function (d) { return d.x })
.attr("cy", function (d) { return d.y })
.attr("transform", function (d) {
return "translate(" + d.x + "," + d.y + ")";
})
});

function update() {
// update links
var link = svg.selectAll('.link').data(graph.links);
link.enter()
.insert('line', '.node')
.attr('class', 'link')
.style('stroke', '#d9d9d9');
link
.exit()
.remove()

// update nodes
var node = svg.selectAll('.node').data(graph.nodes);
var g = node.enter()
.append('g')
.attr('class', 'node');
g.append('circle')
.attr("r", 20)
.style("fill", "#d9d9d9");
g.append('text')
.attr("class", "text")
.text(function (d) { return d.name });
node
.exit()
.remove();

// update simulation
simulation
.linkDistance(100)
.charge(-200)
.start();
};

function addNode(node) {
graph.nodes.push(node);
update();
};

function connectNodes(source, target) {
graph.links.push({
source: source,
target: target,
});
update();
};

addNode({
id: "you",
name: "you",
});

let index = 1;

// add a new node every three seconds and connect to 'you'
const interval = window.setInterval(() => {
let id = Math.random().toString(36).replace('0.','');
id = id.slice(0,4);
addNode({
id: id,
name: id
});

connectNodes(0, index);
index++;
}, 3000);

// no more than 8 nodes
setTimeout(() => {
clearInterval(interval)
}, 3000 * 8);
<html>
<head>
<script src="https://d3js.org/d3.v3.min.js"></script>
</head>
<body>
<svg width="400" height="200"></svg>
</body>
</html>

以下代码片段我尝试使用 d3js v7 实现上述代码片段:

var svg = d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height");

graph = {
nodes: [],
links: [],
}

var simulation = d3.forceSimulation()
.force("center", d3.forceCenter(width / 2, height / 2).strength(0.01))
.nodes(graph.nodes)
.force("link", d3.forceLink(graph.links).distance(100))
.on("tick", function() {
svg.selectAll('.link')
.attr("x1", function (d) { return d.source.x })
.attr("y1", function (d) { return d.source.y })
.attr("x2", function (d) { return d.target.x })
.attr("y2", function (d) { return d.target.y })

svg.selectAll('.node')
.attr("cx", function (d) { return d.x })
.attr("cy", function (d) { return d.y })
.attr("transform", function (d) {
return "translate(" + d.x + "," + d.y + ")";
})
});

function update() {
// update links
var link = svg.selectAll('.link').data(graph.links);
link.enter()
.insert('line', '.node')
.attr('class', 'link')
.style('stroke', '#d9d9d9');
link
.exit()
.remove()

// update nodes
var node = svg.selectAll('.node').data(graph.nodes);
var g = node.enter()
.append('g')
.attr('class', 'node');
g.append('circle')
.attr("r", 20)
.style("fill", "#d9d9d9");
g.append('text')
.attr("class", "text")
.text(function (d) { return d.name });
node
.exit()
.remove();

// update simulation
simulation
.nodes(graph.nodes)
.force("link", d3.forceLink(graph.links).distance(100))
.force("charge", d3.forceManyBody().strength(-200))
.restart()
};

function addNode(node) {
graph.nodes.push(node);
update();
};

function connectNodes(source, target) {
graph.links.push({
source: source,
target: target,
});
update();
};

addNode({
id: "you",
name: "you",
});

let index = 1;

// add a new node every three seconds and connect to 'you'
const interval = window.setInterval(() => {
let id = Math.random().toString(36).replace('0.','');
id = id.slice(0,4);
addNode({
id: id,
name: id
});

connectNodes(0, index);
index++;
}, 3000);

// no more than 8 nodes
setTimeout(() => {
clearInterval(interval)
}, 3000 * 8);
<html>
<head>
<script src="https://d3js.org/d3.v7.min.js"></script>
</head>
<body>
<svg width="400" height="200"></svg>
</body>
</html>

d3js v7 代码片段不会产生与 d3js v3 相同的结果 - 为什么会这样?在这个差异中可以看到我所做的确切更改: https://www.diffchecker.com/wdq7AFbU .
即使不添加任何连接,两种实现之间也存在差异。 v3 实现使“you”节点从随机方向飞入,而在 v7 实现中,“you”节点始终从同一方向飞入。
由于 v7 实现中的新节点卡在左上角,因此施加力的方式似乎也存在一些差异。

最佳答案

我注意到 DOM 的属性反射(reflect)了正常的状态。只是模拟过早地停止了。
简而言之,默认值d3.force.alphaDecay对预期结果来说太短了 ; alphaDecay指示模拟的结束。尝试将值扩大一点。 alphaDecay 的最新默认值为 0.001,根据 d3-force github readme .在我的测试 session 中,将值设置为 1/5(0.0002)似乎足以获得相同的结果。
尝试运行下面的代码。它工作正常。
提示
使用 DOM 和 SVG 时,尝试添加匹配的 data-ooo标记以查看 d3.selection工作正常。我添加了节点数据的属性,例如 .index.target , .source到像 data-index,data-id,data-target,data-source... 这样的属性并注意到一切就绪。

var svg = d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height");

graph = {
nodes: [],
links: [],
}

var simulation = d3.forceSimulation()
.force("center", d3.forceCenter(width / 2, height / 2).strength(0.01))
.nodes(graph.nodes)
.force("link", d3.forceLink(graph.links).distance(100))
.on("tick", function() {
svg.selectAll('.link')
.attr("x1", function (d) { return d.source.x })
.attr("y1", function (d) { return d.source.y })
.attr("x2", function (d) { return d.target.x })
.attr("y2", function (d) { return d.target.y })

svg.selectAll('.node')
.attr("cx", function (d) { return d.x })
.attr("cy", function (d) { return d.y })
.attr("transform", function (d) {
return "translate(" + d.x + "," + d.y + ")";
})
}).alphaDecay(0.0002) // just added alpha decay to delay end of execution

function update() {
// update links
var link = svg.selectAll('.link').data(graph.links);
link.enter()
.insert('line', '.node')
.attr('class', 'link')
.style('stroke', '#d9d9d9');
link
.exit()
.remove()

// update nodes
var node = svg.selectAll('.node').data(graph.nodes);
var g = node.enter()
.append('g')
.attr('class', 'node');
g.append('circle')
.attr("r", 20)
.style("fill", "#d9d9d9");
g.append('text')
.attr("class", "text")
.text(function (d) { return d.name });
node
.exit()
.remove();

// update simulation
simulation
.nodes(graph.nodes)
.force("link", d3.forceLink(graph.links).distance(100))
.force("charge", d3.forceManyBody().strength(-200))
.restart()
};

function addNode(node) {
graph.nodes.push(node);
update();
};

function connectNodes(source, target) {
graph.links.push({
source: source,
target: target,
});
update();
};

addNode({
id: "you",
name: "you",
});

let index = 1;

// add a new node every three seconds and connect to 'you'
const interval = window.setInterval(() => {
let id = Math.random().toString(36).replace('0.','');
id = id.slice(0,4);
addNode({
id: id,
name: id
});

connectNodes(0, index);
index++;
}, 3000);

// no more than 8 nodes
setTimeout(() => {
clearInterval(interval)
}, 3000 * 8);
<html>
<head>
<script src="https://d3js.org/d3.v7.min.js"></script>
</head>
<body>
<svg width="400" height="200"></svg>
</body>
</html>

编辑:什么是 alpha 和 alphaDecay?

doing simulation.restart().alpha(0.3) seem to give the same effect which was mentioned in an answer to my earlier post. Is there any difference between the two?


d3-force github 自述文件说 阿尔法代表熵。简而言之, 阿尔法代表模拟的生命周期; alpha=1 代表开始,alpha=0 代表结束。

https://github.com/d3/d3-force#simulation_alpha

alpha is roughly analogous to temperature in simulated annealing. It decreases over time as the simulation “cools down”. When alpha reaches alphaMin, the simulation stops


这是一个简单的伪代码来说明这个想法。
alpha = 1
alphaDecay = 0.002
function tick() {
alpha = alpha - alphaDecay
}

loop {
tick()
if alpha equals to 0 then end simulation
}
评论中提到的先前答案增加了 阿尔法重新启动时,因为他想在重置后给模拟更多时间。
在我的回答中,我设置了 alphaDecay 到较低的数字,以便模拟可以工作更长的时间。
  • 增加 alphaDecay/减少 alpha = 模拟结束得更快
  • 减少 alphaDecay/增加 alpha = 模拟稍后结束

  • 编辑:自 D3 v4 以来 d3-force 的变化?

    Also, there is still some difference between the v3 and v7 implementation; 1) the collisions in v3 is more elastic and 2) the new nodes being added come in from random directions. Do you know what could be fixed to get 1) and 2) in the v7 implementation?


    请阅读 d3-force v1 github changelog ;自 d3 v4 以来,d3-force 成为一个单独的包,此更改日志解释了这些更改。
    1. d3-force 变得更加准确。
    变更日志提到了许多改进:

    The force simulation now uses velocity Verlet integration rather than position Verlet, tracking the nodes’ positions (node.x, node.y) and velocities (node.vx, node.vy) rather than their previous positions (node.px, node.py).The new link force replaces force.linkStrength and employs better default heuristics to improve stability.


    d3-force 的物理集成得到了改进,以提高准确性。这就是为什么它看起来与 v3 实现不同的原因。
    尽管可以以特定方式调整模拟外观,但 more elastic 是什么?意思是?这是否意味着更强的反作用力?还是意味着更快的动画(但在相同的时间内)? 它肯定可以调整,只有在请求更详细的情况下。 而且每个 d3 包的结构和公式都非常简单。可以 look inside并改变其内在功能。
    2. 操作节点位置
    https://github.com/d3/d3-force#simulation_nodes
    操纵 .x.y模拟期间的节点以改变它们的位置。
    addNode({ id: /* ... */, x: 0, y: 100}) // like this
    编辑:关于 alpha 和时间的增减关系,我的回答中有一些错别字。

    关于javascript - 将 d3.layout.force v3 更新到 d3.forceSimulation v7,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73023097/

    34 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com