2016-07-07 7 views
6

Использование ориентированного на усиление макета в d3, как мне сделать расстояние ссылки приоритетным, сохраняя при этом хороший график? неd3 force направленная компоновка - приоритет расстояния линии

Если я указываю динамические расстояния линии связи, но держать заряд по умолчанию, мой график расстояния MorphEd немного с помощью функции заряда, и больше не точные расстояния:

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: // github.com/d3/d3-force/blob/master/README.md#link_distance для v4 вы можете указать расстояние ссылки http://plnkr.co/edit/12D55owSNuDnSH0hNfWu?p = info, но я не уверен, что вы ищете выше. – Cyril

ответ

3

Если я правильно понимаю, я считаю, что существует потенциальное решение.

Чтобы получить точное расстояние ссылки, вам необходимо установить силу зарядов и столкновений в ноль, но по мере того, как ваше изображение подсказывает, узлы не располагаются так, что учитываются другие узлы, а только те узлы, которые они разделяют ссылки. Поскольку d3.force инициализирует узлы, которые не имеют значений x, y в компоновке филлотаксиса, ссылки и узлы будут группироваться непреднамеренно. Но, применяя силу отталкивания во время моделирования, расстояние увеличивается, но расстояния искажаются.

Возможное решение заключается в использовании силы отталкивания изначально, потому что вам необходимо разделить узлы на узнаваемые кластеры на основе ссылок. Затем, после того, как они будут разделены, уменьшите силу отталкивания до нуля, чтобы единственное усилие было применено относительно желаемого расстояния.

Это требует от вас изменения сил в функции галочки по мере развития графика. Это также требует, чтобы все расстояния между ссылками были совместимы друг с другом (треугольник узлов не может иметь два угла, разделенных на 100 пикселей, а оставшийся угол связан с двумя другими на 10 пикселей).

Что-то подобное может работать в пределах функции клеща в простых ситуациях:

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, или увеличить его для более простых.

Я сделал простой пример здесь, в конце визуализации расстояния регистрируются (я увеличил 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

Это довольно плохой контроль с моей стороны, не знаю, почему я это сделал. Спасибо, что указали это. –

 Смежные вопросы

  • Нет связанных вопросов^_^