2012-11-30 19 views
5

Il mio obiettivo è utilizzare il layout di forza d3 per visualizzare due reti diverse che condividono gli stessi nodi. Ad esempio, tra quattro persone, è possibile definire un social network e una rete di genealogia; i nodi sarebbero uguali (persone) ma i collegamenti (relazioni) potrebbero essere diversi. Nonostante la creazione di due layout di forza separati, due tele svg separate e cercando di definire variabili separate, i nodi condividono le informazioni posizionali x e y. Ecco un esempio minimo, in cui trascinare i nodi su una rete cambia le loro posizioni nelle altre reti: http://amath.colorado.edu/student/larremore/nodesSharingPositiond3Più istanze di layout di forza d3 sulla stessa pagina

Qui di seguito, ho postato la funzione che è chiamata a creare una delle reti, e il codice per creare il l'altro è molto simile, ma utilizza nomi di variabili diversi in tutte le istanze. Il codice commentato per la creazione di entrambe le reti può essere trovato in http://amath.colorado.edu/student/larremore/nodesSharingPositiond3/lib/minimal.js e lo script utilizzato per definire le variabili può essere trovato in /driver/minimalScript.js < - Non ho abbastanza reputazione per collegarlo direttamente. Mie scuse!

Da qualche parte nel modo in cui funziona d3.force, le informazioni sulla posizione sono globali o vengono selezionate globalmente o qualcosa del genere. Qualcuno potrebbe far luce su questo? Sono interessato sia a una soluzione per mantenere separate le informazioni posizionali sia a capire come d3.force gestisce e aggiorna i calcoli delle posizioni.

function makeYNet() { 

// This populates the YactiveLinks variable with the proper YLinks. The goal is to be able to only display links whose value is above some threshold. 
for (var i=0; i<YLinks.length; i++) { 
    if (YLinks[i].link2 > thr) { 
     YactiveLinks.push(YLinks[i]); 
    } 
} 

// Add nodes and links to forceY 
forceY 
.nodes(YNodes) 
.links(YactiveLinks); 

// Draw lines 
var Ylink = svgY.selectAll("line.link") 
.data(YactiveLinks) 
.enter() 
.append("line") 
.attr("class", "link") 
.style("stroke-width", 2.0); 

// Draw nodes 
var Ynode = svgY.selectAll("circle.node") 
.data(YNodes) 
.enter().append("circle") 
.attr("class", "node") 
.attr("r", radius) 
.attr("high",0) 
.attr("id", function(d,i) { 
     return ("idy" + i); 
     }) 
.style("fill", function(d) { return color(d.group1); }) 
.call(forceY.drag) 
; 

// Define tick 
forceY.on("tick", function() { 
      Ylink 
      .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; }); 

      Ynode.attr("cx", function(d) { return d.x; }) 
      .attr("cy", function(d) { return d.y; }); 
      }); 

// Start 'er up 
forceY.start(); 
} 
+0

Sto provando a fare la stessa cosa: sincronizzare le posizioni dei nodi di due layout di forza sulla stessa pagina. Ho due layout di forza che funzionano grazie alla risposta di Alex Reynolds. Tuttavia, non capisco dove impostare i ganci per la sincronizzazione della posizione.Dal momento che i collegamenti all'approccio di DBLaremore non funzionano più, qualcuno ha un suggerimento da dove iniziare o forse collega ad un altro esempio? – tty56

risposta

4

ho scritto uno strumento che permette la navigazione biologica regulatory networks, che mostra due pannelli SVG side-by-side. Ogni pannello contiene una rete di layout di forza, come disegnata dall'API d3.js.

Ho scoperto che la chiave per fare questo lavoro è dare a ogni elemento del DOM un nome univoco, dove possono esserci duplicati.

Nel mio caso, ho utilizzato _left e _right come sufficiente per ogni elemento del pannello, dove l'elemento si trova nel pannello sinistro o destro, rispettivamente. È molto lavoro da tenere a mente, ma il renderer di rete può indirizzare le sue chiamate e gli eventi all'elemento e alla rete corretti.

Nel tuo caso:

.attr("id", function(d,i) { 
     return ("idx" + i); 
     }) 

Si desidera sostituire il valore return con qualcosa che si rivolge in modo univoco la rete che il nodo è associato. Sia che si utilizzi uno schema di numerazione dell'indice o un approccio basato su suffissi, come ho fatto io, il trucco è assicurarsi che tutti i nomi id siano univoci.

+0

L'esempio del tuo sito è buono da imitare: sembra fantastico! Tuttavia, non sono in grado di risolvere il mio problema cambiando gli id. Ho provato a utilizzare id diversi, così come nessun id, e in entrambi i casi i display si stanno ancora aggiornando a vicenda. Ho controllato che i nomi per sinistra (X) e destra (Y) differiscono nei nomi del layout, dei nodi, dei collegamenti e delle tele svg. Qualche altro suggerimento? Non so se questo è rilevante, ma se trascini e tenga una rete abbastanza a lungo, l'altra si raffredderà/bloccherà e quindi non sarà più collegata (apparentemente). – DBLarremore

+0

Non so cos'altro potrebbe funzionare. So che assicurarsi che ogni singolo elemento in ogni rete sia unico è la chiave per far funzionare questo. Se esistono nomi duplicati 'id', le cose si interrompono. Vorrei poter essere di più aiuto! –

+0

Un'altra cosa che ho notato che (forse) fornisce un indizio: Dopo un certo periodo di tempo/dissipazione, il layout congeleranno i nodi nella loro posizione attuale. Se prendi il layout a sinistra e lo sposti fino a quando non si blocca correttamente, non sarai più in grado di spostare il layout giusto in modo indiretto. Quindi, se prendi il layout giusto, puoi usarlo per influenzare la sinistra ** solo ** finché la sinistra non si blocca. Per me, questo implica che mentre le posizioni del layout possono essere influenzate, il timer di raffreddamento non è influenzato da quel movimento. I nodi si muovono in entrambi i grafici, ma solo uno registra le dinamiche. – DBLarremore

0

Javascript è noto per offuscare se lo stato è condiviso o meno. Il tuo esempio minimo non è più disponibile, ma quando ho riscontrato lo stesso problema, la mia conclusione è stata che stavo facendo solo copie poco profonde dove avevo bisogno di cloni completi. (Sto parlando dei collegamenti e nodi che D3 prende come input.)

Senza una copia, il comportamento risultante sarà un po 'casuale, come hai scoperto, a seconda se il codice D3 sceglie di modificare i dati condivisi "in situ" o no. In generale, D3 tenta non per creare copie, per motivi di prestazioni.

Questo è il motivo per cui la soluzione di chiamata json funziona: completamente stringendo tutti i dati, si sta forzando di fatto un'operazione di clonazione.

Problemi correlati