To make a Graphviz hierarchy read like an indented outline on your Mac, give each node a row and an indentation coordinate, then render with neato -n2. This preserves parent–child edges while letting you control the reading order.

This walkthrough creates a six-node example and exports a PDF. The target is specific: one node per line, descendants immediately below their parent, and equal indentation for nodes at the same depth. Graphviz documents fixed-position rendering through its -n command-line option.

Why doesn’t a normal Graphviz tree look like an outline?

A hierarchy describes relationships; an indented outline also specifies a reading sequence. In this example, the root contains two branches, and the first branch’s descendants must appear before the second branch. The desired order is:

Node R
    Node A
        Node C
        Node D
    Node B
        Node E

The graph’s relationships are root to A, root to B, A to C, A to D, and B to E. There is no relationship from D to B merely because B appears on the next line. DOT expresses directed edges with the -> operator; node declarations and their presentation attributes are separate parts of the language. See the official DOT Language reference.

Graphviz’s dot engine produces hierarchical or layered drawings. It aims edges in a common direction while attempting to reduce crossings and edge lengths. That objective suits a branching diagram, but it does not define the one-row-per-node outline shown above. See the dot layout documentation.

Several familiar attributes address only part of the problem:

Setting Documented purpose What it leaves unresolved
rankdir=LR Changes the layout direction to left to right Does not specify a vertical outline sequence
rank=same Places a subgraph’s nodes on the same rank Does not assign every node its own outline row
ordering=out Constrains outgoing edges to appear left to right in input order Does not define depth-based indentation and row coordinates

These boundaries follow the official references for rankdir, rank, and ordering. For the exact row arrangement in this article, explicit coordinates provide a more direct construction than combining those attributes.

How do you prepare Graphviz on a Mac?

Open Terminal. If you already use Homebrew, install Graphviz with the following command. The official Graphviz download page lists this Mac installation method:

brew install graphviz

If you use MacPorts instead, the same download page lists sudo port install graphviz. Choose the package manager you already use. If neither is installed, follow the relevant installation link from that page before returning to this walkthrough.

Check that the renderer is available:

neato -V

The -V option prints Graphviz version information. Keep the reported version when comparing results across computers; you do not need a particular version number printed in this article. Graphviz documents this option in its Command Line reference.

How do you create the indented hierarchy?

The following complete shell block creates a new working folder and writes the DOT file there. Run it in Terminal; the folder path will be printed when it finishes. The quoted heredoc delimiter preserves the DOT text as written.

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

The node positions encode the outline. Each successive row moves down by 48 points, and each additional depth moves right by 36 points. Those numbers are illustrative spacing choices, not Graphviz defaults. The pos documentation specifies that node positions refer to node centers and that neato interprets positions as points when used with -n.

Node Depth Row, starting at zero Center position
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

For this construction, the coordinate rules are x = 100 + 36 × depth and y = 300 − 48 × row. Notice the return from Node D to Node B: the row advances, but the depth decreases. That single transition is what makes the drawing read as an outline instead of a chain.

All boxes have the same dimensions, so equal center coordinates also align their left edges. The equal-length synthetic labels make the text placement easy to compare. With fixedsize=true, Graphviz uses the specified node dimensions rather than enlarging boxes to fit their contents; oversized labels generate a warning. See the fixedsize reference.

How do you render and inspect the result?

In the same Terminal session and working folder, run:

neato -n2 -Tpdf hierarchy.dot -o hierarchy.pdf

Here, -n2 keeps the supplied node arrangement without overlap adjustment and calculates routes for edges that lack their own positions. Every node therefore needs a pos value. The -Tpdf and -o options select PDF output and its destination. These behaviors are documented in the Command Line reference.

Open the working folder in Finder and open hierarchy.pdf. PDF output requires a Graphviz build that includes the Cairo renderer, as specified on Graphviz’s PDF output page. The example has been checked against the documentation, but it has not been render-tested here because Graphviz was unavailable in the research environment.

Inspect three things separately:

  1. Read downward: R, A, C, D, B, E should occupy successive rows.
  2. Compare indentation: A and B should align; C, D, and E should align one step farther right.
  3. Trace relationships: R connects to A and B; A connects to C and D; B connects to E.

The first two checks assess the coordinate construction. The third checks the actual graph. Keeping those checks separate helps catch a diagram that looks orderly but contains an incorrect parent–child edge.

Will the connectors look exactly like a file browser’s tree?

The node rows and indentation are explicitly specified; the connector paths are still calculated. The example requests splines=ortho, which routes edges through axis-aligned segments. Graphviz’s documentation also states that this routing does not handle ports, so adding compass ports is not a documented way to force a particular elbow pattern. See the splines reference.

Consequently, this construction provides an indented hierarchy with automatically routed right-angle connectors. It does not prescribe a single shared vertical rail with precisely placed branch junctions. If that connector geometry is essential, it requires an additional construction with explicitly specified edge paths; splines=ortho alone does not express that requirement.

For a clean outline without visible connectors, change the graph setting to splines=none and render again. The DOT file still contains its parent–child edges, while the renderer omits their strokes. This is a documented rendering option in the same splines reference.

How do you adapt the example without changing its meaning?

Start by writing the intended reading order independently of the edge list. Visit a parent first, then its first child and that child’s descendants, before moving to the next child. Assign one row to every node in that sequence. Then assign indentation from depth.

For example, to add another child beneath Node A after Node D, insert it into the reading sequence before Node B. Give it depth two, move the later rows downward, and add an edge from A to the new node. The existing parent relationships do not change merely because their row numbers change.

Use the following diagnostic sequence when an edited version looks wrong:

  • The drawing spreads into a different arrangement: confirm that the command still uses neato -n2. The example relies on supplied positions rather than ordinary automatic layout.
  • Rendering reports a missing position: check every node ID, including IDs mentioned only in edge statements. Each needs a positioned declaration for this workflow.
  • A label extends beyond its box: increase the common box dimensions or shorten the label. Fixed-size boxes do not expand automatically.
  • Rows overlap after enlarging boxes: increase the row interval. The chosen rendering mode preserves positions instead of correcting overlaps.
  • A branch connects to the wrong node: correct the edge statement. Moving a box cannot repair an incorrect relationship.

The missing-position and overlap conditions follow Graphviz’s documented -n2 behavior; the label condition follows its fixedsize behavior. Increasing spacing is the corresponding design adjustment for this manually positioned example.

Keep the hierarchy’s edge list as the source of relationships and the coordinate table as the source of presentation. For a small Mac desktop diagram, that separation makes the result straightforward to maintain: change edges when the hierarchy changes, change rows when the reading order changes, and change spacing when the labels need more room.

Sources