2016-07-07 14 views
6

D3'te bir kuvvet-yönlendirmeli mizanpaj kullanarak, iyi bir grafik düzenini korurken bağlantı mesafesini nasıl bir öncelik haline getirebilirim?d3 kuvvet yönelimli düzen - bağlantı mesafesi önceliği

Ben dinamik bağlantı mesafeleri belirtmek, ancak varsayılan şarj tutarsanız, benim grafik mesafeleri yükleme fonksiyonu tarafından biraz Morphed? Elde edilen artık doğru mesafeleri: Ancak

enter image description here

, ben kaldırırsanız ücret, grafik şöyle görünür:

enter image description here

Herhangi tavsiye takdir!

+2

buraya bakın likSistance ve linkStrength http://bl.ocks.org/sathomas/774d02a21dc1c714def8 bu size yardımcı olmalıdır. – Cyril

+1

Fiş için teşekkürler Cyril. Kitabımın D3 bölümüyle birlikte web sayfamdaki tam metnini de okuyabilirsiniz: [http://jsDataV.is] (http://jsDataV.is) –

+0

Bu https: // 'i görmüş olabileceğinizi umuyorum v4 için github.com/d3/d3-force/blob/master/README.md#link_distance bir bağlantı mesafesi verebilir http://plnkr.co/edit/12D55owSNuDnSH0hNfWu?p = info ama yukarıdakileri aradığınızdan emin değilim. – Cyril

cevap

3

Doğru anlıyorsam, olası bir çözüm olduğuna inanıyorum.

Bağlantı mesafesinin doğru olması için, yük ve çarpışma kuvvetlerini sıfıra ayarlamanız gerekir, ancak görüntünüzün belirttiği gibi, düğümler diğer düğümleri hesaba katacak şekilde değil, yalnızca paylaştıkları düğümlerdir. ile bağlantılar. D3.force, phyllotaxis düzenlemesinde x, y değerlerine sahip olmayan düğümleri başlattıkça, bağlantılar ve düğümler istenmeyen şekillerde kümelenir. Ancak, simülasyon boyunca itici bir kuvvet uygulandığında, boşluklar iyileştirilir ancak mesafeler bozulur.

Olası çözüm, başlangıçta düğümleri bağlantılara dayalı tanınabilir kümelere ayırmanız gerektiğinden, bir itme gücü kullanmaktır. Daha sonra, ayrıldıktan sonra, itme kuvvetini hiçbir şeye düşürmeyin, böylece uygulanan tek kuvvet istenen bağlantı mesafesine göre olur.

Bu, grafik geliştikçe kene işlevindeki kuvvetleri değiştirmenizi gerektirir. Bu ayrıca tüm bağlantı mesafelerinin birbiriyle uyumlu olmasını gerektirir (düğümlerin üçgeni 100 pikselle ayrılmış iki köşeye ve diğer iki piksele 10 piksele bağlı kalan köşeye sahip olamaz). alphaDecay azaltarak serin aşağı için daha fazla zaman izin verebilir, daha karmaşık görsel için

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 
} 

veya daha basit olanlar için bunu artırmaya: Böyle

şey basit durumlarda kene fonksiyonu içinde çalışabilir.

Buraya basit bir örnek verdim, görselleştirme mesafelerinin sonunda günlüğe kaydedilir (hassaslık maliyetini hızlandırmak için aşağıdaki parçacıklarda alphaDecay'i artırdım, ancak yine de oldukça iyi) ve başvurulan istenilen mesafelerle.

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>

grafiğin karmaşıklığına bağlı olarak, zaman soğumasını uyarlamak için itici kuvvet gücü gerekebilir ve alfa, velocityDecay soğutur olarak bunu nasıl değiştirdiğini (potansiyel olarak değiştirerek kene işlevi) ve/veya mesafe kuvveti kendisi.

+0

Bu güzel bir çözüm! Koşuda güçleri değiştirmek için hiç bir zaman olmadı. Diğer uygulamalarda da işe yarayabileceği için bunu aklımda tutacağım. Ödül çok iyi kazanıldı! – altocumulus

+0

Anlayamadığım bir şey, simulasyonun ilk kurulumunda "link" kuvvetini geçersiz kılmanız gerçeğidir. Sadece isim için son güç kullanılacaktır, bu biraz fazlalık gibi görünüyor. Buna biraz ışık tutabilir misin? – altocumulus

+0

Bu, neden benim yaptığımdan emin değilim. İşaret ettiğin için teşekkürler. –

İlgili konular