GraphViz - ¿Cómo conectar subgrafos?

166

En el DOTlenguaje para GraphViz, estoy tratando de representar un diagrama de dependencia. Necesito poder tener nodos dentro de un contenedor y poder hacer que los nodos y / o contenedores dependan de otros nodos y / o contenedores.

Estoy usando subgraphpara representar mis contenedores. La vinculación de nodos funciona bien, pero no puedo entender cómo conectar subgráficos.

Dado el programa a continuación, necesito poder conectarme cluster_1y cluster_2con una flecha, pero todo lo que he intentado crea nuevos nodos en lugar de conectar los grupos:

digraph G {

    graph [fontsize=10 fontname="Verdana"];
    node [shape=record fontsize=10 fontname="Verdana"];

    subgraph cluster_0 {
        node [style=filled];
        "Item 1" "Item 2";
        label = "Container A";
        color=blue;
    }

    subgraph cluster_1 {
        node [style=filled];
        "Item 3" "Item 4";
        label = "Container B";
        color=blue;
    }

    subgraph cluster_2 {
        node [style=filled];
        "Item 5" "Item 6";
        label = "Container C";
        color=blue;
    }

    // Renders fine
    "Item 1" -> "Item 2";
    "Item 2" -> "Item 3";

    // Both of these create new nodes
    cluster_1 -> cluster_2;
    "Container A" -> "Container C";
}

ingrese la descripción de la imagen aquí

Winston Smith
fuente
2
Tengo el mismo problema, pero tienen un ejemplo natural en el que los subgrafos actúan como nodos, graphviz.org/content/fdpclust .
nlucaroni
1
@nlucaroni, me pregunto si este problema está resuelto. Este ejemplo me da un gráfico incorrecto: los bordes conectan los centros del subgráfico. ¿No sabes cómo hacer que funcione como en el ejemplo?
k102
1
@ K102, lo sé. Mira esa página nuevamente; dice que necesitas usar fdp. El ejemplo vinculado y el de arriba funcionan (la última línea del ejemplo aquí necesita usar los nombres de los subgrafos, no la etiqueta, y podría ser bueno incluir longitudes de línea para el gráfico); es un poco apretado como es).
nlucaroni
1
@nlucaroni Utilizando fdpv2.28.0 y copiando / pegando la fuente del ejemplo, las líneas se conectan al centro del subgrafo, no a los bordes. Si abre el .dot en OmniGraffle, están conectados correctamente, neatoy dotambos crean nodos superfluos para el clúster.
Phrogz

Respuestas:

190

El manual del usuario del DOT ofrece el siguiente ejemplo de un gráfico con grupos con bordes entre grupos:

IMPORTANTE: compound=truese requiere la declaración inicial .

digraph G {
  compound=true;
  subgraph cluster0 {
    a -> b;
    a -> c;
    b -> d;
    c -> d;
  }
  subgraph cluster1 {
    e -> g;
    e -> f;
  }
  b -> f [lhead=cluster1];
  d -> e;
  c -> g [ltail=cluster0,lhead=cluster1];
  c -> e [ltail=cluster0];
  d -> h;
}

... y bordes entre nodos y grupos:

ingrese la descripción de la imagen aquí

Marca de alto rendimiento
fuente
14
Gracias, eso funciona, pero realmente se siente como un truco feo. Estoy esperando que no tienen un escenario en el que tengo un recipiente con ningún nodo.
Winston Smith
55
En caso de que alguien esté interesado, esto puede causar problemas de posicionamiento si ha etiquetado enlaces (bordes). Si bien la cabeza o la cola del borde pueden estar ocultos debajo de un grupo, la etiqueta todavía está posicionada en el punto medio, lo que significa que algunas etiquetas de borde parecen estar flotando sobre un grupo en lugar de estar posicionadas por el borde mismo.
Winston Smith
58
@ WinstonSmith: Antigua pregunta, pero tuve un problema similar y lo resolví con un nodo ficticio invisible por grupo, al que se puede vincular incluso si el grupo está vacío de lo contrario. DUMMY_0 [shape=point style=invis]
DevSolar
2
Encontré que los bordes entre grupos se contraían solo para puntas de flecha, cuando se usan grupos que solo están conectados verticalmente. Lo arreglé con minlen = 1 en los bordes. c -> g [ltail = cluster0, lhead = cluster1, minlen = 1];
Freenerd
3
Aquí está el enlace al manual con el ejemplo: graphviz.org/Documentation/dotguide.pdf (página 30).
Kirill Bulygin
90

Para facilitar la referencia, la solución descrita en la respuesta de HighPerformanceMark, aplicada directamente a la pregunta original, se ve así:

digraph G {

    graph [fontsize=10 fontname="Verdana" compound=true];
    node [shape=record fontsize=10 fontname="Verdana"];

    subgraph cluster_0 {
        node [style=filled];
        "Item 1" "Item 2";
        label = "Container A";
        color=blue;
    }

    subgraph cluster_1 {
        node [style=filled];
        "Item 3" "Item 4";
        label = "Container B";
        color=blue;
    }

    subgraph cluster_2 {
        node [style=filled];
        "Item 5" "Item 6";
        label = "Container C";
        color=blue;
    }

    // Edges between nodes render fine
    "Item 1" -> "Item 2";
    "Item 2" -> "Item 3";

    // Edges that directly connect one cluster to another
    "Item 1" -> "Item 3" [ltail=cluster_0 lhead=cluster_1];
    "Item 1" -> "Item 5" [ltail=cluster_0 lhead=cluster_2];
}

El compound=trueen la graphdeclaración es vital. Eso produce salida:

gráfico con grupos conectados

Tenga en cuenta que cambié los bordes a los nodos de referencia dentro del clúster, agregué los atributos ltail y lhead a cada borde, especificando el nombre del clúster y agregué el atributo de nivel de gráfico 'compuesto = verdadero'.

Con respecto a la preocupación de que uno quiera conectar un clúster sin nodos dentro de él, mi solución ha sido siempre agregar un nodo a cada clúster, representado con estilo = texto sin formato. Use este nodo para etiquetar el clúster (en lugar del atributo de "etiqueta" incorporado del clúster, que debe establecerse en la cadena vacía (en Python label='""'). Esto significa que ya no agrego bordes que conectan los clústeres directamente, pero Funciona en mi situación particular.

Jonathan Hartley
fuente
24
Nota: 'graph [fontsize = 10 fontname = "Verdana" composite = true];' es esencial, si echa de menos que vincular a ltail / lhead no funciona.
s.Daniel
1
@ JonathanHartley, Según su último párrafo, ¿hay alguna forma de centrar ese nodo justo en el medio del clúster?
Pacerier
también el nombre del clúster no debe comenzar con una letra mayúscula
JCLL
77
@ s.Daniel Es solo el compuesto = verdadero; que se requiere
Dr. Max Völkel
En lugar de reiniciar lhead y ltail cuando enlace "Elemento 1" -> "Elemento 3", ¿cómo puedo vincular cluster_0 y cluster_1 con un código significativo? Meam, hacer cluster_0 -> cluster_1presente como salida. Debido a que puede haber muchos elementos en el cluster_0, enlace a otros muchos elementos en el cluster_1 (muchos a muchos o uno a muchos). Sería bueno solo vincular dos.
Mithril
11

Asegúrese de estar utilizando el fdpdiseño para el archivo. No creo que neatoadmita grupos.

mihajlv
fuente
2
Yo también he encontrado experimentalmente que el neatomotor no admite grupos .. No estoy seguro si esto es un error o no ..
Ross Rogers