GraphViz - Como conectar subgráficos?

166

Na DOTlinguagem para GraphViz, estou tentando representar um diagrama de dependência. Eu preciso ter nós dentro de um contêiner e poder tornar nós e / ou contêineres dependentes de outros nós e / ou contêineres.

Estou usando subgraphpara representar meus contêineres. A vinculação de nó funciona muito bem, mas não consigo descobrir como conectar subgráficos.

Dado o programa abaixo, preciso conectar-me cluster_1e cluster_2com uma seta, mas qualquer coisa que tentei cria novos nós em vez de conectar os clusters:

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";
}

insira a descrição da imagem aqui

Winston Smith
fonte
2
Estou tendo o mesmo problema, mas eles têm um exemplo natural em que os subgráficos estão agindo como nós, graphviz.org/content/fdpclust .
Nlucaroni
1
@nlucaroni Gostaria de saber se este problema está resolvido. Este exemplo me fornece um gráfico errado: as bordas conectam os centros do subgráfico. você não sabe como fazê-lo funcionar como no exemplo?
K102
1
@ k102, eu sei. Confira essa página novamente; diz que você precisa usar fdp. O exemplo vinculado e o acima de ambos funcionam (a última linha do exemplo aqui precisa usar os nomes dos subgráficos e não o rótulo e pode ser bom incluir comprimentos de linha no gráfico); está um pouco apertado como está).
Nlucaroni
1
@nlucaroni Usando a fdpv2.28.0 e copiando / colando a fonte do exemplo, as linhas se conectam ao centro do subgráfico, não às bordas. Se você abrir o .dot em OmniGraffle estão conectados corretamente, enquanto neatoe dottanto criar nós supérfluos para o cluster.
Phrogz

Respostas:

190

O manual do usuário do DOT fornece o seguinte exemplo de gráfico com clusters com arestas entre clusters:

IMPORTANTE: A compound=truedeclaração inicial é necessária.

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;
}

... e arestas entre nós e clusters:

insira a descrição da imagem aqui

Marca de alto desempenho
fonte
14
Obrigado - isso funciona, mas realmente parece um truque feio. Eu estou esperando que eu não tenho um cenário onde eu tenho um recipiente com nenhum nó.
Winston Smith
5
Caso alguém esteja interessado, isso pode causar problemas de posicionamento se você tiver rotulado links (arestas). Embora a cabeça ou a cauda da borda possa estar oculta sob um cluster, o rótulo ainda está posicionado no ponto médio, o que significa que alguns rótulos de borda parecem flutuar sobre um cluster em vez de serem posicionados pela própria borda.
Winston Smith
58
@WinstonSmith: Pergunta antiga, mas eu tive um problema semelhante e o resolvi com um nó fictício invisível por cluster, que pode ser vinculado mesmo que o cluster esteja vazio. DUMMY_0 [shape=point style=invis]
DevSolar
2
Eu descobri que minhas arestas entre aglomerados estavam reduzidas a apenas setas, ao usar clusters que são conectados apenas verticalmente. Corrigi isso com minlen = 1 nas bordas. c -> g [ltail = cluster0, lhead = cluster1, minlen = 1];
Freenerd
3
Aqui está o link para o manual com o exemplo: graphviz.org/Documentation/dotguide.pdf (página 30).
precisa saber é o seguinte
90

Para facilitar a referência, a solução descrita na resposta do HighPerformanceMark, aplicada diretamente à pergunta original, tem a seguinte aparência:

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];
}

O compound=truena graphdeclaração é vital. Isso produz saída:

gráfico com clusters conectados

Observe que eu alterei as arestas para referenciar os nós no cluster, adicionei os atributos ltail e lhead a cada borda, especificando o nome do cluster e adicionei o atributo no nível do gráfico 'composite = true'.

Com relação à preocupação de que alguém possa querer conectar um cluster sem nós, minha solução foi sempre adicionar um nó a cada cluster, renderizado com style = plaintext. Use esse nó para rotular o cluster (em vez do atributo "label" interno do cluster, que deve ser definido como a sequência vazia (em Python label='""'). Isso significa que não estou mais adicionando arestas que conectam clusters diretamente, mas funciona na minha situação particular.

Jonathan Hartley
fonte
24
Nota: 'graph [fontsize = 10 fontname = "Verdana" composto = true];' é essencial - se você perder esse vínculo com o ltail / lhead não funcionará.
s.Daniel
1
@ JonathanHartley, de acordo com o seu último parágrafo, existe alguma maneira de centralizar esse nó no meio do cluster?
Pacerier
também o nome do cluster não deve começar por uma letra maiúscula
JCLL 9/09/16
7
@ s.Daniel É apenas o composto = true; que é exigido
Dr. Max Völkel
Em vez de redefinir lhead e ltail quando vincular "Item 1" -> "Item 3", como vincular cluster_0 e cluster_1 com código significativo? Eu meam, faça cluster_0 -> cluster_1presente como você produz . Porque pode haver muitos itens no cluster_0 vinculados a outros itens no cluster_1 (muitos para muitos ou um para muitos). Seria bom apenas ligar dois.
Mithril
11

Verifique se você está usando o fdplayout do arquivo. Eu não acho que neatosuporta clusters.

mihajlv
fonte
2
Eu também tenho encontrado experimentalmente que o neatomotor não suporta clusters .. Eu não tenho certeza se este é um bug ou não ..
Ross Rogers