Para que uma hierarquia do Graphviz tenha a aparência de um esquema recuado no Mac, atribua a cada nó uma linha e uma coordenada de recuo e, em seguida, renderize com neato -n2. Isso preserva as arestas entre pais e filhos e permite controlar a ordem de leitura.
Este passo a passo cria um exemplo com seis nós e exporta um PDF. O objetivo é específico: um nó por linha, descendentes logo abaixo do pai e o mesmo recuo para nós na mesma profundidade. O Graphviz documenta a renderização com posições fixas por meio de sua opção de linha de comando -n.
Por que uma árvore comum do Graphviz não parece um esquema?
Uma hierarquia descreve relações; um esquema recuado também especifica uma sequência de leitura. Neste exemplo, a raiz contém dois ramos, e os descendentes do primeiro ramo devem aparecer antes do segundo ramo. A ordem desejada é:
Node R
Node A
Node C
Node D
Node B
Node E
As relações do grafo são da raiz para A, da raiz para B, de A para C, de A para D e de B para E. Não há relação de D para B só porque B aparece na linha seguinte. A linguagem DOT expressa arestas direcionadas com o operador ->; as declarações dos nós e seus atributos de apresentação são partes separadas da linguagem. Consulte a referência oficial da linguagem DOT.
O mecanismo dot do Graphviz produz desenhos hierárquicos ou em camadas. Ele orienta as arestas em uma direção comum e tenta reduzir cruzamentos e comprimentos das arestas. Esse objetivo é adequado a um diagrama ramificado, mas não define o esquema com um nó por linha mostrado acima. Consulte a documentação de layout do dot.
Vários atributos conhecidos resolvem apenas parte do problema:
| Configuração | Finalidade documentada | O que não resolve |
|---|---|---|
rankdir=LR |
Muda a direção do layout para da esquerda para a direita | Não especifica uma sequência vertical para o esquema |
rank=same |
Coloca os nós de um subgrafo na mesma classificação | Não atribui uma linha própria do esquema a cada nó |
ordering=out |
Restringe as arestas de saída para que apareçam da esquerda para a direita, na ordem de entrada | Não define o recuo baseado na profundidade nem as coordenadas das linhas |
Esses limites são descritos nas referências oficiais de rankdir, rank e ordering. Para o arranjo exato de linhas deste artigo, as coordenadas explícitas oferecem uma construção mais direta do que combinar esses atributos.
Como preparar o Graphviz no Mac?
Abra o Terminal. Se você já usa o Homebrew, instale o Graphviz com o comando a seguir. A página oficial de download do Graphviz lista esse método de instalação no Mac:
brew install graphviz
Se você usa o MacPorts, a mesma página de download lista sudo port install graphviz. Escolha o gerenciador de pacotes que você já usa. Se nenhum estiver instalado, siga o link de instalação correspondente nessa página antes de continuar este passo a passo.
Verifique se o renderizador está disponível:
neato -V
A opção -V exibe informações sobre a versão do Graphviz. Guarde a versão informada ao comparar resultados entre computadores; não é necessária uma versão específica mencionada neste artigo. O Graphviz documenta essa opção em sua referência de linha de comando.
Como criar a hierarquia recuada?
O bloco completo de shell a seguir cria uma nova pasta de trabalho e grava o arquivo DOT nela. Execute-o no Terminal; o caminho da pasta será exibido ao terminar. O delimitador entre aspas do heredoc preserva o texto DOT como está escrito.
outline_dir=$(mktemp -d "$HOME/graphviz-outline.XXXXXX")
if [ -n "$outline_dir" ] && cd "$outline_dir"; then
cat > hierarchy.dot <<'DOT'
digraph Hierarchy {
graph [splines=ortho, bgcolor=white];
node [
shape=box,
width=1.2,
height=0.35,
fixedsize=true,
fontname="Courier",
fontsize=12
];
r [label="Node R", pos="100,300"];
a [label="Node A", pos="136,252"];
c [label="Node C", pos="172,204"];
d [label="Node D", pos="172,156"];
b [label="Node B", pos="136,108"];
e [label="Node E", pos="172,60"];
r -> a;
r -> b;
a -> c;
a -> d;
b -> e;
}
DOT
pwd
fi
As posições dos nós codificam o esquema. Cada linha sucessiva desce 48 pontos, e cada nível adicional de profundidade avança 36 pontos para a direita. Esses números são escolhas ilustrativas de espaçamento, não valores padrão do Graphviz. A documentação de pos especifica que as posições dos nós se referem aos seus centros e que neato interpreta as posições em pontos quando usado com -n.
| Nó | Profundidade | Linha, começando em zero | Posição do centro |
|---|---|---|---|
| Node R | 0 | 0 | 100,300 |
| Node A | 1 | 1 | 136,252 |
| Node C | 2 | 2 | 172,204 |
| Node D | 2 | 3 | 172,156 |
| Node B | 1 | 4 | 136,108 |
| Node E | 2 | 5 | 172,60 |
Nesta construção, as regras de coordenadas são x = 100 + 36 × depth e y = 300 − 48 × row. Observe o retorno de Node D para Node B: a linha avança, mas a profundidade diminui. Essa transição é o que faz o desenho parecer um esquema, em vez de uma cadeia.
Todas as caixas têm as mesmas dimensões, então as coordenadas iguais dos centros também alinham suas bordas esquerdas. Os rótulos sintéticos de mesmo comprimento facilitam a comparação da posição do texto. Com fixedsize=true, o Graphviz usa as dimensões de nó especificadas em vez de ampliar as caixas para acomodar o conteúdo; rótulos grandes demais geram um aviso. Consulte a referência de fixedsize.
Como renderizar e inspecionar o resultado?
Na mesma sessão do Terminal e na pasta de trabalho, execute:
neato -n2 -Tpdf hierarchy.dot -o hierarchy.pdf
Aqui, -n2 mantém o arranjo fornecido para os nós sem ajuste para evitar sobreposições e calcula os trajetos das arestas que não têm posições próprias. Portanto, todos os nós precisam de um valor pos. As opções -Tpdf e -o selecionam a saída em PDF e o destino dela. Esses comportamentos estão documentados na referência de linha de comando.
Abra a pasta de trabalho no Finder e abra hierarchy.pdf. A saída em PDF requer uma compilação do Graphviz que inclua o renderizador Cairo, conforme especificado na página de saída em PDF do Graphviz. O exemplo foi conferido com base na documentação, mas não foi testado por renderização aqui porque o Graphviz não estava disponível no ambiente de pesquisa.
Inspecione três aspectos separadamente:
- Leia de cima para baixo: R, A, C, D, B, E devem ocupar linhas sucessivas.
- Compare os recuos: A e B devem ficar alinhados; C, D e E devem ficar alinhados um nível mais à direita.
- Acompanhe as relações: R se conecta a A e B; A se conecta a C e D; B se conecta a E.
As duas primeiras verificações avaliam a construção das coordenadas. A terceira verifica o grafo propriamente dito. Manter essas verificações separadas ajuda a identificar um diagrama que parece organizado, mas contém uma aresta incorreta entre pai e filho.
Os conectores terão exatamente a aparência da árvore de um navegador de arquivos?
As linhas dos nós e o recuo são especificados explicitamente; os trajetos dos conectores ainda são calculados. O exemplo solicita splines=ortho, que traça as arestas usando segmentos alinhados aos eixos. A documentação do Graphviz também declara que esse tipo de traçado não lida com portas, portanto, adicionar portas de bússola não é uma maneira documentada de forçar um padrão específico de ângulos retos. Consulte a referência de splines.
Consequentemente, esta construção fornece uma hierarquia recuada com conectores em ângulo reto roteados automaticamente. Ela não prescreve um único trilho vertical compartilhado com junções dos ramos posicionadas com precisão. Se essa geometria dos conectores for essencial, será necessária uma construção adicional com trajetos de arestas especificados explicitamente; splines=ortho por si só não expressa esse requisito.
Para obter um esquema limpo, sem conectores visíveis, mude a configuração do grafo para splines=none e renderize novamente. O arquivo DOT ainda contém as arestas entre pais e filhos, mas o renderizador omite seus traços. Essa é uma opção de renderização documentada na mesma referência de splines.
Como adaptar o exemplo sem mudar seu significado?
Comece escrevendo a ordem de leitura pretendida independentemente da lista de arestas. Visite primeiro um pai, depois seu primeiro filho e os descendentes desse filho, antes de passar ao próximo filho. Atribua uma linha a cada nó nessa sequência. Em seguida, defina o recuo conforme a profundidade.
Por exemplo, para adicionar outro filho abaixo de Node A, após Node D, insira-o na sequência de leitura antes de Node B. Atribua a ele a profundidade dois, desloque as linhas posteriores para baixo e adicione uma aresta de A ao novo nó. As relações entre pais não mudam simplesmente porque os números das linhas mudaram.
Use a seguinte sequência de diagnóstico quando uma versão editada parecer incorreta:
- O desenho se espalha em um arranjo diferente: confirme que o comando ainda usa
neato -n2. O exemplo depende das posições fornecidas, não do layout automático comum. - A renderização informa que falta uma posição: verifique todos os IDs dos nós, inclusive os mencionados apenas em declarações de arestas. Neste fluxo de trabalho, cada um precisa de uma declaração com posição definida.
- Um rótulo ultrapassa os limites da caixa: aumente as dimensões comuns das caixas ou encurte o rótulo. Caixas de tamanho fixo não se expandem automaticamente.
- As linhas se sobrepõem após o aumento das caixas: aumente o intervalo entre as linhas. O modo de renderização escolhido preserva as posições em vez de corrigir as sobreposições.
- Um ramo se conecta ao nó errado: corrija a declaração da aresta. Mover uma caixa não corrige uma relação incorreta.
As condições de posição ausente e sobreposição seguem o comportamento documentado de -n2 no Graphviz; a condição do rótulo segue o comportamento de fixedsize. Aumentar o espaçamento é o ajuste de design correspondente para este exemplo posicionado manualmente.
Use a lista de arestas da hierarquia como fonte das relações e a tabela de coordenadas como fonte da apresentação. Para um pequeno diagrama de desktop no Mac, essa separação facilita a manutenção do resultado: altere as arestas quando a hierarquia mudar, altere as linhas quando a ordem de leitura mudar e altere o espaçamento quando os rótulos precisarem de mais espaço.