2016-07-07 2 views
6

d3에서 강제 지시 레이아웃을 사용하면 좋은 그래프 레이아웃을 유지하면서 링크 거리를 우선 순위로 만들 수 있습니까?d3 강제 지시 레이아웃 - 링크 간격 우선 순위

내가 동적 링크 거리를 지정하지만, 기본 요금을 유지하는 경우, 내 그래프 거리가 충전 기능에 의해 약간 변신하고 있습니다되어 더 이상 정확한 거리 없습니다 : 그러나

enter image description here

, 내가 제거하는 경우 충전이 그래프는 다음과 같습니다

enter image description here

어떤 조언을 감사합니다!

+2

여기를 참조 likDistance 및 linkStrength http://bl.ocks.org/sathomas/774d02a21dc1c714def8이 도움이됩니다. – Cyril

+1

플러그 용 시리우스 감사합니다. 내 웹 사이트 : D3에 관한 장을 포함하여 내 책의 전체 텍스트를 읽을 수도 있습니다. [http://jsDataV.is] (http://jsDataV.is) –

+0

https : // v4에 대한 github.com/d3/d3-force/blob/master/README.md#link_distance 링크를 제공 할 수 있습니다 http://plnkr.co/edit/12D55owSNuDnSH0hNfWu?p = 정보하지만 당신이 위를 찾고 있는지 확실하지 않습니다. – Cyril

답변

3

내가 올바르게 이해하면 잠재적 인 해결책이 있다고 생각합니다.

정확한 링크 거리를 얻으려면 요금과 충돌 세력을 0으로 설정해야하지만 이미지에서 알 수 있듯이 노드는 다른 노드, 즉 공유하는 노드 와 연결됩니다. d3.force가 x, y 값을 가지지 않는 노드를 축약 문자 배열로 초기화하므로 링크와 노드가 의도하지 않은 방식으로 클러스터됩니다. 그러나 시뮬레이션을 통해 반발력을 적용하면 간격이 개선되지만 거리가 왜곡됩니다.

가능한 해결책은 링크를 기반으로 노드를 인식 가능한 클러스터로 분리해야하기 때문에 처음에는 반발력을 사용하는 것입니다. 그런 다음, 이들이 분리 된 후에 반발력을 아무 것도 아닌 것으로 감소시켜 적용된 힘만이 원하는 링크 거리와 관련되도록하십시오.

그래프가 진화하면 틱 기능에서 힘을 수정해야합니다. 또한 모든 링크 거리가 서로 호환되어야합니다 (삼각형의 노드는 두 개의 모서리를 100 픽셀로 구분할 수없고 나머지 모서리는 다른 두 모서리와 10 픽셀 씩 연결할 수 없음). alphaDecay 감소하여 멋진 아래로 더 많은 시간을 허용 할 수있는, 더 복잡한 시각화를 들어

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를 증가 시켰지만 여전히 좋습니다) 참조 된 원하는 거리와.

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}, 
 
\t {source: 3, target: 13, distance: 2}, 
 
\t {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)) 
 
\t .force("link", d3.forceLink().distance(function(d) { return d.distance }).strength(2)) 
 
    .force("center", d3.forceCenter(width/2, height/2)) 
 
\t .force("collide",d3.forceCollide().strength(0).radius(0)) 
 
\t .alphaDecay(0.03) 
 
    .velocityDecay(0.4); 
 
\t 
 
\t 
 
\t 
 
    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) 
 
\t 
 
simulation 
 
     .nodes(graph.nodes) 
 
     .on("tick", ticked); 
 

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

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

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

 
\t this.force("charge", d3.forceManyBody().strength(-30 * chargeStrength)) 
 
\t 
 
\t 
 
    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; }); 
 
\t \t 
 
\t // validate: 
 
\t if (alpha < 0.001) { 
 
\t \t link.each(function(d,i) { 
 
\t \t 
 
\t \t \t var a = d.source.x - d.target.x; 
 
\t \t \t var b = d.source.y - d.target.y; 
 
\t \t  var c = Math.pow(a*a + b*b, 0.5); 
 
\t \t \t 
 
\t \t \t console.log("specified length: " + graph.links[i].distance + ", realized distance: " + c); 
 
\t \t }) 
 
\t } 
 
    }
.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>

그래프의 복잡도에 따라, 당신은 시간을 냉각 맞게 반발력 강도를해야 할 수도 있습니다 및 알파, velocityDecay를 냉각으로 당신이 그것을 변경하는 방법 (잠재적으로 그것을 수정 눈금 기능) 및/또는 거리 힘 그 자체.

+0

그건 멋진 솔루션입니다! 러닝에서 세력을 수정하는 일은 절대로 내게 일어나지 않았습니다. 다른 응용 프로그램에서도 도움이 될 수 있으므로이 점을 명심하십시오. 현상금은 아주 잘 받았습니다! – altocumulus

+0

그러나 내가 알 수없는 한 가지는 시뮬레이션의 초기 설정에서 링크를 무시하는 것입니다. 이름에 대한 마지막 힘만 사용되기 때문에 이것은 다소 중복 된 것처럼 보입니다. 이것에 대해 좀 밝혀 주시겠습니까? – altocumulus

+0

그것은 내가 왜 그렇게했는지 확신 할 수없는 내 부분에 대한 아주 나쁜 감시이다. 그것을 지적 주셔서 감사합니다. –

관련 문제