d3强制定向布局-链接距离优先级 [英] d3 force directed layout - link distance priority

查看:131
本文介绍了d3强制定向布局-链接距离优先级的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在d3中使用力导向布局,如何在保持良好图形布局的同时将链接距离作为优先级?

Using a force-directed layout in d3, how do I make the link distance a priority, while still keeping a nice graph layout?

如果我指定了动态链接距离,但保留了默认电荷,则电荷功能会使我的图形距离有些变形,不再是精确的距离:

If I specify dynamic link distances, but keep the default charge, my graph distances are morphed a bit by the charge function, and are no longer accurate distances:

但是,如果我取消扣款,该图将如下所示:

However, if I remove the charge, the graph looks like this:

任何建议表示赞赏!

推荐答案

如果我理解正确,我相信有潜在的解决方案.

If I understand correctly, I believe there is a potential solution.

要使链接距离准确,您需要将电荷和碰撞力设置为零,但是正如您的图像所暗示的那样,节点之间的间距不会考虑其他节点,仅是它们共享链接的那些节点和.当d3.force初始化在叶轴排列中不具有x,y值的节点时,链接和节点将以意想不到的方式聚集.但是,如果在整个模拟过程中都施加排斥力,则可以改善间距,但距离会失真.

To get link distance to be accurate, you need to set charge and collision forces to zero, but as your image suggests, then nodes aren't spaced in a way that accounts for other nodes, just those nodes which they share links with. As d3.force initializes nodes that do not have x,y values in a phyllotaxis arrangement, links and nodes will be clustered in unintended ways. But, if applying a repelling force throughout the simulation, the spacing is improved but the distances are distorted.

可能的解决方案是最初使用排斥力,因为您需要根据链接将节点分成可识别的群集.然后,在将它们分开后,将排斥力减小至零,以使施加的唯一力与所需的链节距离有关.

The possible solution is to use a repelling force initially because you need to separate nodes into recognizable clusters based on links. Then, after they are separated, reduce the repelling force to nothing so that the only force applied is in relation to the desired link distance.

这要求您在图形演变时修改刻度函数中的力.这还要求所有链接距离彼此兼容(节点的三角形不能有两个角相隔100个像素,其余角不能与其他两个角相隔10个像素).

This requires you to modify the forces in the tick function as the graph evolves. This also requires that all link distances are compatible with one another (a triangle of nodes can't have two corners separated by 100 pixels and the remaining corner connected to the other two by 10 pixels).

在简单情况下,类似的事情可能会在tick函数中起作用:

Something like this might work within the tick function in simple situations:

var alpha = this.alpha();   // starts at 1 by default, simulation ends at zero

var chargeStrength; // a multiplier for charge strength

if ( alpha > 0.2 ) {
    chargeStrength = (alpha - 0.2 / 0.8); // decrease for the first portion of the simulation
}
else {
    chargeStrength = 0; // leave at zero and give the link distance force time to work without competing forces
}

对于更复杂的可视化,您可以通过减少alphaDecay来增加冷却时间,或者对于更简单的可视化来增加冷却时间.

For more complex visualizations, you could allow more time for cool down by decreasing alphaDecay, or increase it for simpler ones.

我在这里做了一个简单的例子,在可视化的末尾记录了距离(我在下面的代码段中增加了alphaDecay以加快精度,但仍相当不错),并引用了所需的距离.

I've made a simple example here, at the end of the visualization distances are logged (I've increased alphaDecay in the snippet below to speed it up at the cost of precision, but it's still pretty good) and referenced with desired distances.

var graph = {
  nodes: d3.range(15).map(Object),
  links: [
    {source:  0, target:  1, distance: 20 },
    {source:  0, target:  2, distance: 40},
    {source:  0, target:  3, distance: 80},
    {source:  1, target:  4, distance: 20},
    {source:  1, target:  5, distance: 40},
    {source:  1, target:  6, distance: 80},
    {source:  2, target:  7, distance: 12},
    {source:  2, target:  8, distance: 8},
    {source:  2, target:  9, distance: 6},
    {source:  3, target:  10, distance: 10},
    {source:  3, target:  11, distance: 10},
    {source:  3, target:  12, distance: 2},
	{source:  3, target:  13, distance: 2},
	{source:  3, target:  14, distance: 2}
  ]
};

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

var color = d3.scaleOrdinal(d3.schemeCategory20);

var simulation = d3.forceSimulation()
    .force("charge", d3.forceManyBody().strength(-30 ))
	.force("link", d3.forceLink().distance(function(d) { return d.distance } ).strength(2) )
    .force("center", d3.forceCenter(width / 2, height / 2))
	.force("collide",d3.forceCollide().strength(0).radius(0))
	.alphaDecay(0.03)
    .velocityDecay(0.4);
	
	
	
  var link = svg.append("g")
      .attr("class", "links")
    .selectAll("line")
    .data(graph.links)
    .enter().append("line")
      .attr("stroke-width", 1);

  var node = svg.append("g")
     .attr("class", "nodes")
    .selectAll("circle")
    .data(graph.nodes)
    .enter().append("circle")
     .attr("r", 3)
	  
 simulation
      .nodes(graph.nodes)
      .on("tick", ticked);

  simulation.force("link")
      .links(graph.links);

  
  
	  
  function ticked() {
	
	var alpha = this.alpha();
	var chargeStrength;

    if ( alpha > 0.2 ) {
		chargeStrength = (alpha - 0.2 / 0.8);
	}
	else {
		chargeStrength = 0;
	}

	this.force("charge", d3.forceManyBody().strength( -30 * chargeStrength ))
	
	
    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; });

    node
        .attr("cx", function(d) { return d.x; })
        .attr("cy", function(d) { return d.y; });
		
	// validate:
	if (alpha < 0.001) {
		link.each(function(d,i) {
		
			var a = d.source.x - d.target.x;
			var b = d.source.y - d.target.y;
		    var c = Math.pow(a*a + b*b, 0.5);
			
			console.log("specified length: " + graph.links[i].distance + ", realized distance: " + c );
		})
	}
  }

.links line {
  stroke: #999;
  stroke-opacity: 0.6;
}

.nodes circle {
  stroke: #fff;
  stroke-width: 1.5px;
}

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>
<svg width="500" height="300"></svg>

取决于图形的复杂性,您可能需要调整冷却时间,排斥力强度以及在alpha冷却时如何改变其强度,VelocityDecay(可能在刻度函数中对其进行修改)和/或距离力本身.

Depending on the complexity of the graph, you might need to tailor cool down time, the repelling force strength and how you alter it as alpha cools, velocityDecay (potentially modifying it in the tick function), and/or the distance force itself.

这篇关于d3强制定向布局-链接距离优先级的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆