2010-05-25 31 views
11

Estoy tratando de crear una estructura de árbol con graphviz. Estoy abierto a escribir el código graphviz a mano o usar la gema ruby-graphviz para ruby. Dada la imagen de abajo ¿alguien puede proporcionar alguna información sobre el código necesario? Ignore que las líneas no son rectas ... deberían estar cuando graphviz construye el gráfico. Estoy abierto a tener puntos/puntos cuando las líneas se cruzan también.complex graphviz tree structure

He jugado con ruby-graphviz y la clase de árbol genealógico ... esto me está llevando a una parte del camino pero realmente necesito que todas las líneas sean rectas y se crucen en ángulo recto y fuera de la el código de caja no parece hacer eso.

El código debe ser lo suficientemente genérico como para permitir que la casilla "C" también tenga hijos y que también haya más niños debajo de "A".

Los colores son irrelevantes ... los ejemplos pueden excluir cualquier coloración.

http://docs.google.com/drawings/pub?id=1lUTfgKP_LN0x7C3ItbsFjfLBuDTL84AtmoaW7YFn32Y&w=1036&h=713

Respuesta

4

Por lo que yo sé que esto requiere un poco de trabajo en torno; Solo lo haré en Graphviz DOT language. Primero te doy la solución y luego te doy algunas explicaciones sobre cómo puedes ampliarla.

Esta es la cifra resultante:

outfile.png

Este es el código Graphviz la producción de la figura:

graph atree { 
    Item1 [shape=none,label="Item 1",pos="2.2,1.1!"]; 
    Item2 [shape=none,label="Item 2",pos="2.2,0.1!"]; 
    Item3 [shape=none,label="Item 3",pos="2.9,-0.3!"]; 
    A [shape=box,color=lightblue,style=filled,pos="2,3!"]; 
    B [shape=box,color=lightblue,style=filled,pos="1,2.1!"]; 
    C [shape=box,color=lightblue,style=filled,pos="3,2.1!"]; 
    D [shape=box,color=lightblue,style=filled,pos="1.5,1.5!"]; 
    E [shape=box,color=lightblue,style=filled,pos="1.5,0.5!"]; 
    D0 [style=invisible,fixedsize=true,width=0,height=0,pos="2,2.5!",label=""]; 
    D1 [style=invisible,fixedsize=true,width=0,height=0,pos="1,2.5!",label=""]; 
    D2 [style=invisible,fixedsize=true,width=0,height=0,pos="3,2.5!",label=""]; 
    D3 [style=invisible,fixedsize=true,width=0,height=0,pos="1,1.5!",label=""]; 
    D4 [style=invisible,fixedsize=true,width=0,height=0,pos="1,0.5!",label=""]; 
    D5 [style=invisible,fixedsize=true,width=0,height=0,pos="1.5,1.1!",label=""]; 
    D6 [style=invisible,fixedsize=true,width=0,height=0,pos="1.5,0.1!",label=""]; 
    D7 [style=invisible,fixedsize=true,width=0,height=0,pos="2.2,-0.3!",label=""]; 
    A -- D0 -- D1 -- B -- D3 -- D4 -- E [color=blue]; 
    E -- D6 -- Item2 -- D7 -- Item3 [color=blue]; 
    D0 -- D2 -- C [color=blue]; 
    D3 -- D -- D5 -- Item1 [color=blue]; 
} 

Si lo pones en un archivo llamado inputfile.dot que pueda obtener la imagen resultante archivo utilizando el comando neato -Tpng inputfile.dot > outfile.png.

Ahora un par de comentarios sobre cómo funciona: El código que construye el árbol con A, B, C, D, E, Item1, Item2, Item3 es sencillo (los atributos simplemente establecen los colores y estilos de caja). El truco para hacer que las líneas sean rectas y ortogonales consiste en 1) agregar nodos invisibles con tamaño cero al gráfico, y 2) posicionar todos los objetos en coordenadas absolutas en el lienzo. Los nodos auxiliares D1, D2, D3, D4, D5, D6, D7 son necesarios para el paso 1) y las opciones pos="x,y!" son necesarias para el paso 2). Tenga en cuenta que necesita el signo ! al final del comando pos, ya que, de lo contrario, las posiciones no se considerarían definitivas y el diseño podría cambiar.

Puede añadir nodos adicionales por primera posicionamiento un nuevo nodo (utilizando el código para los nodos A ... Item3 como una plantilla), añadiendo una, nodo auxiliar invisible (con pos de tal manera que todas las conexiones hacia y desde él son ortogonales) y luego agregando la conexión al gráfico a través de <StartingNode> -- <AuxiliaryNode> -- <NewNode>.

+0

lo que parece que mi código tendrá que hacer la parte difícil de averiguar los números de posicionamiento absoluto! – thomas

+0

Desafortunadamente, no conozco ninguna forma de usar Graphviz que dibuje el gráfico con enlaces ortogonales (y divisiones) entre nodos. Si no requiere este comportamiento, Graphviz hará la mayor parte del trabajo duro por usted. Si insiste en este comportamiento, me temo que tendrá que hacer un trabajo manual para el diseño. – user8472

+0

gracias. Necesito este comportamiento desafortunadamente. tendré que codificar esta lógica. – thomas

12

Un poco tarde, lo sé, pero solo quería mostrar otra versión sin tener que averiguar las posiciones exactas de cada nodo.

digraph { 
    splines=false; 
    ranksep=0.05; 

    node[shape=box, color=lightblue, style=filled]; 
    A;B;C;D;E; 

    node[shape=none, color=none, style=solid]; 
    i1[label="Item 1"]; 
    i2[label="Item 2"]; 
    i3[label="Item 3"]; 

    node[label="", width=0, height=0]; 
    edge[arrowhead=none, color=blue]; 

    {rank=same; n2; n1; n3;} 
    n2; n1; n3; 
    A -> n1; 
    n2 -> n1 -> n3; 

    {rank=same; B; C;} 
    n2 -> B; 
    n3 -> C; 

    {rank=same; n4; D;} 
    B -> n4 -> D; 

    {rank=same; n6; n5; i1;} 
    D -> n5 -> i1; 
    n4 -> n6; 

    {rank=same; n7; E;} 
    n6 -> n7 -> E; 

    {rank=same; n8; i2;} 
    E -> n8 -> i2; 

    {rank=same; n9; i3;} 
    i2 -> n9 -> i3; 
} 

Las líneas rectas se hacen cumplir por:

  • splines=false - diga no a las estrías
  • nodos invisibles (nodos N1, N2, ...N9)
  • nodos puesta en el mismo rango con rank=same

Es todavía un poco de trabajo para obtener el archivo de punto correcto, pero es mejor que en mi humilde opinión el cálculo de sí mismo la posición de cada nodo.

salida se parece a esto:

graphviz output

Mientras C no tiene nodos secundarios, que tendría que aplicar un poco más engaños (nodos invisibles) para mostrar todo el camino a la derecha.

Para obtener una solución más general para diferentes gráficos, es probable que se necesiten algunas adaptaciones adicionales (aplicar peso a los bordes verticales, o nodos de grupo que deben estar alineados verticalmente, o usar subgrafos, ...).

+0

Nota: no funciona correctamente con las últimas versiones de GraphViz. 'splilines = ortho' podría usarse en su lugar si elimina los nodos ocultos externos http://stackoverflow.com/a/36953206/1312346 –

3

Todavía otra versión que usa splines=ortho, que necesita menos nodos ocultos y da un resultado visual similar.

digraph example { 
    splines=ortho; 
    ranksep=0.05; 

    node[shape=box, color=lightblue, style=filled]; 
    A;B;C;D;E; 

    node[shape=none, color=none, style=solid]; 
    i1[label="Item 1"]; 
    i2[label="Item 2"]; 
    i3[label="Item 3"]; 

    node[label="", width=0, height=0]; 
    edge[arrowhead=none, color=blue]; 
    n1; n2; n3; n4; n5; 

    {rank=same; B; C;} 
    A -> n1; 
    n1 -> B; 
    n1 -> C; 

    {rank=same; n2; D;} 
    B -> n2; 
    n2 -> D; 

    {rank=same; n3; i1;} 
    D -> n3; 
    n3 -> i1; 

    {rank=same; n4; E;} 
    n2 -> n4; 
    n4 -> E; 

    {rank=same; n5; i2;} 
    E -> n5; 
    n5 -> i2; 

    {rank=same; n6; i3;} 
    i2 -> n6; 
    n6 -> i3; 
} 

dot image drawn via PlantUML.com