PGF/TikZ Manual | PGFplots | TikZ Editor

TikZ and PGF Manual

Graph Drawing

30 Graph Drawing Layouts: Trees

by Till Tantau

30.1 The Tree Layouts
30.1.1 The Reingold–Tilford Layout
30.2 Specifying Missing Children

In the present section we discuss keys for specifying missing children in a tree. For many certain kind of trees, in particular for binary trees, there are not just “a certain number of children” at each node, but, rather, there is a designated “first” (or “left”) child and a “second” (or “right”) child. Even if one of these children is missing and a node actually has only one child, the single child will still be a “first” or “second” child and this information should be taken into consideration when drawing a tree.

The first useful key for specifying missing children is missing number of children which allows you to state how many children there are, at minimum.

Once the minimum number of children has been set, we still need a way of specifying “missing first children” or, more generally, missing children that are not “at the end” of the list of children. For this, there are three methods:

30.3 Spanning Tree Computation

Although the algorithms of this library are tailored to layout trees, they will work for any graph as input. First, if the graph is not connected, it is decomposed into connected components and these are laid out individually. Second, for each component, a spanning tree of the graph is computed first and the layout is computed for this spanning tree; all other edges will still be drawn, but they have no impact on the placement of the nodes. If the graph is already a tree, the spanning tree will be the original graph.

The computation of the spanning tree is a non-trivial process since a non-tree graph has many different possible spanning trees. You can choose between different methods for deciding on a spanning tree, it is even possible to implement new algorithms. (In the future, the computation of spanning trees and the cycle removal in layered graph drawing algorithms will be unified, but, currently, they are implemented differently.)

Selects the (sub)algorithm that is to be used for computing spanning trees whenever this is requested by a tree layout algorithm. The default algorithm is breadth first spanning tree.

(-tikz- diagram)

\usetikzlibrary {graphs,graphdrawing} \usegdlibrary {trees}
\tikz \graph [tree layout, breadth first spanning tree]
{
1 -- {2,3,4,5} -- 6;
};

(-tikz- diagram)

\usetikzlibrary {graphs,graphdrawing} \usegdlibrary {trees}
\tikz \graph [tree layout, depth first spanning tree]
{
1 --[bend right] {2,3,4,5 [>bend left]} -- 6;
};
  • /graph drawing/breadth first spanning tree=string

  • This key selects “breadth first” as the (sub)algorithm for computing spanning trees. Note that this key does not cause a graph drawing scope to start; the key only has an effect in conjunction with keys like tree layout. The algorithm will be called whenever a graph drawing algorithm needs a spanning tree on which to operate. It works as follows:

    • 1. It looks for a node for which the root parameter is set. If there are several such nodes, the first one is used. If there are no such nodes, the first node is used.

      Let call the node determined in this way the root node.

    • 2. For every edge, a priority is determined, which is a number between 1 and 10. How this happens, exactly, will be explained in a moment. Priority 1 means “most important” while priority 10 means “least important”.

    • 3. Starting from the root node, we now perform a breadth first search through the tree, thereby implicitly building a spanning tree: Suppose for a moment that all edges have priority 1. Then, the algorithm works just the way that a normal breadth first search is performed: We keep a queue of to-be-visited nodes and while this queue is not empty, we remove its first node. If this node has not yet been visited, we add all its neighbors at the end of the queue. When a node is taken out of the queue, we make it the child of the node whose neighbor it was when it was added. Since the queue follows the “first in, first out” principle (it is a fifo queue), the children of the root will be all nodes at distance \(1\) form the root, their children will be all nodes at distance \(2\), and so on.

    • 4. Now suppose that some edges have a priority different from 1, in which case things get more complicated. We now keep track of one fifo queue for each of the ten possible priorities. When we consider the neighbors of a node, we actually consider all its incident edges. Each of these edges has a certain priority and the neighbor is put into the queue of the edge’s priority. Now, we still remove nodes normally from the queue for priority 1; only if this queue is empty and there is still a node in the queue for priority 2 we remove the first element from this queue (and proceed as before). If the second queue is also empty, we try the third, and so on up to the tenth queue. If all queues are empty, the algorithm stops.

    The effect of the ten queues is the following: If the edges of priority \(1\) span the whole graph, a spanning tree consisting solely of these edges will be computed. However, if they do not, once we have visited reachable using only priority 1 edges, we will extend the spanning tree using a priority 2 edge; but then we once switch back to using only priority 1 edges. If neither priority 1 nor priority 2 edges suffice to cover the whole graph, priority 3 edges are used, and so on.

  • /graph drawing/depth first spanning tree=string

  • Works exactly like breadth first spanning tree (same handling of priorities), only the queues are now lifo instead of fifo.

  • /graph drawing/root=boolean(default true)

  • This Boolean parameter is used in the computation of spanning trees. When can be set for a node, this node will be used as the root for the spanning tree computation. If several nodes have this option set, the first node will be used.

  • /graph drawing/span priority=number

  • Explicitly sets the “span priority” of an edge to number, which must be a number between 1 and 10. The priority of edges is used by spanning tree computations, see breadth first spanning tree.

  • /graph drawing/span priority reversed ->=number(initially 9)

  • When you write


    graph { a -> b -- c <- [span priority=2] d }

    there are, in addition to the priorities indicated above, also further edge priorities: The priority of the (reversed) edge b to a is span priority reversed ->, the priority of the (reversed) edge c to b is span priority reversed --, and the span priority of the reversed edge d to c is 2, regardless of the value of span priority reversed <-.

    The defaults for the priorities are:

    • span priority reversed -> = 9

    • span priority reversed -- = 5

    • span priority reversed <-> = 5

    • span priority reversed <- = 7

    • span priority reversed -!- = 10

    The default priorities are set in such a way, that non-reversed -> edges have top priorities, -- and <-> edges have the same priorities in either direction, and <- edges have low priority in either direction (but going a <- b from b to a is given higher priority than going from a to b via this edge and also higher priority than going from b to a in a -> b).

    Keys like span using directed change the priorities “en bloc”.