Creating this tree structure with LaTeX

diagramstikz-trees

I would like to easily create tree-like structures like

D─┬───────────┬───A
  R─┬───A─┬─A R─┐  
    R─┐   R     R  
      R 

D is the top root node. It starts a horizontal line to the right, which stands for the "same level". This horizontal line can have more letters A threaded at any position, which do not have additional semantic meaning. These letters A always have a line incoming from the left.

The more interesting feature is that a horizontal line can split downwards to a child (base) node R which always have a line incoming from the top. This split can happen at multiple positions on the horizontal baseline. The child nodes recursively start a new virtual block and hence are usually continued by an outgoing horizontal line to the right.- Hence, the R next to the D effectively starts the whole thing again in its own "bounding box" (here marked with +).

D─┬───────────────┬───A
  +++++++++++     R─┐
 +R─┬───A─┬─A+      R 
 +  R─┐   R  +     
 +    R      + 
  +++++++++++

If for a node there are no more nodes connected to the right, then the horizontal outgoing line is not shown. And of course tree/text overlap needs to be avoided, i.e. some horizontal lines need to stretch far enough before starting a new child node. A type A node also should only appear after all previous child blocks have completed to the left of them.

What would be the best way to create such a tree-like drawing in LaTeX?

I've found \usetikzlibrary{trees} which goes in this direction, but I'm not sure how to flip the example, how to make multiple letters on a horizontal line, how to control text overlap, etc…

Any good suggestion how to recreate that diagram?

There is a working answer with manually positioning everything, but I hope there is another solution like tikz-tree which can calculate the positioning automatically for me, so that I only specify the child-node relations.

With arbitrary and longer labels:

D─┬───────────────────────G─┬─────C
  Cc─┬─────────Aa─┬──Aaaa   Eee─┐  
     Bbb─┐        Dd            A  
         Aaaaa 

Best Answer

Variant with parameter for label

Adaptations

  • see original variant below for more description
  • \nodeD, \nodeR and \nodeA each have now one parameter to set the text.
  • Here I used relative positioning instead of absolute. Therefore, different text lengths are considered.
  • I set base node/.style={draw, dashed} just for clarification

Result

enter image description here

Code

\documentclass[border=2mm]{standalone}

\usepackage{etoolbox}
\usepackage{tikz}
\usetikzlibrary{positioning}

\def\nodedistance{5mm}
\def\treeY{0}

\newcounter{treeRnode}
\setcounter{treeRnode}{0}
\newcounter{treeAnode}
\setcounter{treeAnode}{0}

\def\lastXnode{}

\newcommand{\nodeD}[1]{%
    \node[D] (D0) at (0,0) {#1};
    \csdef{treeLastY\treeY}{D0}
    \xdef\lastXnode{D0}
}

\newcommand{\nodeR}[1]{%
    \pgfmathtruncatemacro\lastY{\treeY}
    \pgfmathtruncatemacro\treeY{\treeY+1}
    \ifcsdef{treeLastY\treeY}{%
        \node[R, anchor=west] (R\arabic{treeRnode}) at ([xshift=\nodedistance] \csuse{treeLastY\treeY}.east-|\lastXnode.east) {#1};
    }{%
        \node[R, below right=of \csuse{treeLastY\lastY}] (R\arabic{treeRnode}) {#1};
    }
    \draw (\csuse{treeLastY\lastY}) -| (R\arabic{treeRnode});
    \csxdef{treeLastY\treeY}{R\arabic{treeRnode}}
    \xdef\lastXnode{R\arabic{treeRnode}}
    \stepcounter{treeRnode}
}

\newcommand{\nodeA}[1]{%
    \node[A, anchor=west] (A) at ([xshift=\nodedistance] \csuse{treeLastY\treeY}.east-|\lastXnode.east) (A\arabic{treeAnode}) {#1};
    \draw (\csuse{treeLastY\treeY}) -- (A\arabic{treeAnode});
    \csxdef{treeLastY\treeY}{A\arabic{treeAnode}}
    \xdef\lastXnode{A\arabic{treeAnode}}
    \stepcounter{treeAnode}
}

\newcommand{\branchend}{%
    \pgfmathtruncatemacro\treeY{\treeY-1}
}

\begin{document}

\begin{tikzpicture}[
    node distance=\nodedistance,
    base node/.style={draw, dashed},
    D/.style={base node},
    R/.style={base node},
    A/.style={base node},
]
    \nodeD{$D_1$ with longer text}
        \nodeR{$R_1$}
            \nodeR{$R_2$ with longer text}
                \nodeR{$R_3$}
                \branchend
            \branchend
        \nodeA{$A_1$}
            \nodeR{$R_4$}
            \branchend
        \nodeA{$A_2$ with longer text}
        \branchend
        %
        \nodeR{$R_5$}
            \nodeR{$R_6$}
            \branchend
        \branchend
    \nodeA{$A_3$}
\end{tikzpicture}

\end{document}

Variant without parameters (original)

Description

I defined some commands that can be used within tikz:

  • \nodeD, \nodeR and \nodeA for the different node types
  • \branchend to stop a branch and go up one level.

I used counters treeRnode and treeAnode to name the nodes and variables \treeX and \treeY to save the current position. Futhermore, \treeLastY<y> saves the last node in layer <y>.

So the code for the given tree is in my syntax:

\nodeD
    \nodeR
        \nodeR
            \nodeR
            \branchend
        \branchend
    \nodeA
        \nodeR
        \branchend
    \nodeA
    \branchend
    %
    \nodeR
        \nodeR
        \branchend
    \branchend
\nodeA

The indentation in the source code is just for readability. So, this would be the same:

\nodeD\nodeR\nodeR\nodeR\branchend\branchend\nodeA\nodeR\branchend\nodeA\branchend\nodeR\nodeR\branchend\branchend\nodeA

Result

enter image description here

Code

\documentclass{article}

\usepackage{etoolbox}
\usepackage{tikz}

\begin{document}

\def\treeX{0}
\def\treeY{0}

\newcounter{treeRnode}
\setcounter{treeRnode}{0}
\newcounter{treeAnode}
\setcounter{treeAnode}{0}

\newcommand{\nodeD}{%
    \node[D] (D0) at (0,0) {D};
    \csdef{treeLastY\treeY}{D0}
}

\newcommand{\nodeR}{%
    \pgfmathtruncatemacro\treeX{\treeX+1}
    \pgfmathtruncatemacro\lastY{\treeY}
    \pgfmathtruncatemacro\treeY{\treeY+1}
    \node[R] (R\arabic{treeRnode}) at (\treeX, -\treeY) {R};
    \draw (\csuse{treeLastY\lastY}) -| (R\arabic{treeRnode});
    \csxdef{treeLastY\treeY}{R\arabic{treeRnode}}
    \stepcounter{treeRnode}
}

\newcommand{\nodeA}{%
    \pgfmathtruncatemacro\treeX{\treeX+1}
    \node[A] (A) (A\arabic{treeAnode}) at (\treeX, -\treeY) {A};
    \draw (\csuse{treeLastY\treeY}) -- (A\arabic{treeAnode});
    \csxdef{treeLastY\treeY}{A\arabic{treeAnode}}
    \stepcounter{treeAnode}
}

\newcommand{\branchend}{%
    \pgfmathtruncatemacro\treeY{\treeY-1}
}

\begin{tikzpicture}[
    base node/.style={},
    D/.style={base node},
    R/.style={base node},
    A/.style={base node},
]
    \nodeD
        \nodeR
            \nodeR
                \nodeR
                \branchend
            \branchend
        \nodeA
            \nodeR
            \branchend
        \nodeA
        \branchend
        %
        \nodeR
            \nodeR
            \branchend
        \branchend
    \nodeA
\end{tikzpicture}

\end{document}