2011-08-11 16 views
9

Qualcuno sa come faccio a tracciare un albero a più vie in modo esteticamente plausibile? informazioni:Disegno e rendering Albero multipiano in Python

  • più o meno 100 articoli
  • ogni livello hanno approssimativamente lo stesso numero di elementi
  • 10 livelli
  • ogni nodo avere tra 0 (foglio) e 6 bambino
  • ciascun nodo specificare il proprio livello, non importa le sue radici.

Attualmente sto usando PIL, dividendo ogni "linea" in img.size()[0]/numero di nodi, e disegnare linee con draw.line per rappresentare bordi, ma è completamente incasinato

spero che possiate help me =], qualsiasi informazione necessaria posterò.

risposta

15

Quindi, il rendering dei grafici è il particolare genio di graphviz, che ha anche diverse librerie che forniscono collegamenti Python. A mio parere, la migliore di queste librerie di bind è pygraphviz. Graphviz è probabilmente la soluzione migliore e probabilmente anche la più semplice.

Il layout particolare si descrive nella sua interrogazione, un gerarchica, schema a strati, viene eseguita senza sforzo da graphviz' dot motore di layout. Il punto esegue il rendering per garantire che il grafico sia disposto in una configurazione ad albero naturale, vale a dire che i nodi padre sono posizionati sopra i propri figli; i nodi di uguale rango (livelli dalla radice) sono equi-posizionati w/r/t l'asse y quando possibile, e la simmetria naturale viene preservata quando possibile.

(Nota: confusamente, dot si riferisce a uno dei diversi motori di layout che compongono graphviz, ma dot è anche il nome e l'estensione di file del formato di file per tutti i documenti graphviz indipendentemente da come sono resi).

Come si può vedere nel mio codice che segue, utilizzando pygraphviz, è semplice selezionare dot come motore di layout per il grafico, anche se non è in realtà il valore di default (neato è).

Ecco un rapido grafico ho fatto e poi resi utilizzando dot --created e reso usando graphviz via pygraphviz.

Si noti che il grafico ha un layout perfetto - i nodi dello stesso grado si trovano sullo stesso livello lungo un asse verticale, i bambini sono resi sotto i genitori e la "simmetria" naturale viene preservata quando possibile (ad esempio, un nodo genitore è posizionato tra e sopra i suoi due nodi figlio. E come puoi vedere, nessuno del mio codice controlla manualmente il layout - graphviz, ovvero punto, lo gestisce automaticamente.

import pygraphviz as PG 

A = PG.AGraph(directed=True, strict=True) 

A.add_edge("7th Edition", "32V") 
A.add_edge("7th Edition", "Xenix") 
# etc., etc. 

# save the graph in dot format 
A.write('ademo.dot') 

# pygraphviz renders graphs in neato by default, 
# so you need to specify dot as the layout engine 
A.layout(prog='dot') 


# opening the dot file in a text editor shows the graph's syntax: 
digraph unix { 
    size="7,5"; 
    node [color=goldenrod2, style=filled]; 
    "7th Edition" -> "32V"; 
    "7th Edition" -> "V7M"; 
    "7th Edition" -> "Xenix"; 
    "7th Edition" -> "UniPlus+"; 
    "V7M" -> "Ultrix-11"; 
    "8th Edition" -> "9th Edition"; 
    "1 BSD" -> "2 BSD"; 
    "2 BSD" -> "2.8 BSD"; 
    "2.8 BSD" -> "Ultrix-11"; 
    "2.8 BSD" -> "2.9 BSD"; 
    "32V" -> "3 BSD"; 
    "3 BSD" -> "4 BSD"; 
    "4 BSD" -> "4.1 BSD"; 
    "4.1 BSD" -> "4.2 BSD"; 
    "4.1 BSD" -> "2.8 BSD"; 
    "4.1 BSD" -> "8th Edition"; 
    "4.2 BSD" -> "4.3 BSD"; 
    "4.2 BSD" -> "Ultrix-32"; 
} 

enter image description here

+0

semplicemente perfetto, devo solo per ottimizzare i layout, i colori, il sangue di Gesù ... grazie. =] – BrainStorm

+0

@doug, mi diresti come imposto il livello del nodo (linea) con un parametro? solo per estetica – BrainStorm

+0

@BrainStorm: beh, solitamente si occupa di questo punto senza alcuna configurazione aggiuntiva. Per forzare la configurazione di questo nodo - impostare un vincolo esplicito - non è difficile, ma richiede due passaggi: (i) definire un "sottografo" (gruppo di nodi nel grafico per avere la stessa posizione orizzontale); e (ii) nella definizione del sottografo, impostare l'attributo 'rank', in questo modo: rank = same. Spazio insufficiente nei commenti per spiegare ulteriormente il sottografo, ma questa pagina fornisce un esempio diretto: http://www.graphviz.org/content/cluster – doug