Recursive method to build a tree with tikz

The following is a possible solution. I had to separate the node creation and the labelling of the edges. I've also been thinking of doing this with a lindenmayer system but that failed. Enjoy. (I minimised on style settings and focussed on the nub of the matter.)

The tree creation wasn't so straightforward and I had to fight hard to increment and decrement the TeX counter \depth. In the end I ended up doing this as part of a node style. It also required the placement of a dummy coordinate that incremented the level upon returning from the recursion.

The labelling exploits the fact that tikz labels the children of a parent with the labels (parent-1), (parent-2), ..., where (parent) is the label of the parent.

The rest is pretty much straightforward.

\documentclass{article}
\usepackage{tikz}      
\usetikzlibrary{calc}  

\newcount\depth

\makeatletter
\newcommand*\bernoulliTree[1]{%
    \depth=#1\relax            
    \draw node(root)[bernoulli/root] {}[grow=right] \draw@bernoulli@tree;
    \draw \label@bernoulli@tree{root};                                   
}                                                                        

\def\draw@bernoulli@tree{%
    \ifnum\depth>0        
      child foreach \type/\label in {left child/$S$,right child/$F$} {%
          node[bernoulli/\type]{\label} \draw@bernoulli@tree
      }
      coordinate[bernoulli/increment] (dummy)
   \fi%
}

\def\label@bernoulli@tree#1{%
    \ifnum\depth>0
      ($(#1)!0.5!(#1-1)$) node[fill=white,bernoulli/decrement] {$p$}
      \label@bernoulli@tree{#1-1}
      ($(#1)!0.5!(#1-2)$) node[fill=white] {$1-p$}
      \label@bernoulli@tree{#1-2}
      coordinate[bernoulli/increment] (dummy)
   \fi%
}

\makeatother

\tikzset{bernoulli/.cd,
         root/.style={circle,fill,black},
         decrement/.code=\global\advance\depth by-1\relax,
         increment/.code=\global\advance\depth by 1\relax,
         left child/.style={draw,bernoulli/decrement},
         right child/.style={draw,circle}}

\begin{document}

\begin{tikzpicture}[level distance=2cm,
                    level 1/.style={sibling distance=4cm},
                    level 2/.style={sibling distance=2cm},
                    level 3/.style={sibling distance=1cm}]
\bernoulliTree{3}
\end{tikzpicture}

\end{document}

sample output


Forest lends itself easily to think kind of automation. The following provides a Forest style, Bernoulli, together with a wrapper macro, \bernoullitree[<options>], which takes one optional argument. As is more common now, and ubiquitous in the TikZ world, configuration uses a key-value interface. If using the macro form, <options> may contain Bernoulli-style-specific keys and/or Forest keys and/or TikZ keys.

One example of the style used directly in a tree and three examples using the macro wrapper are given.

\begin{forest}
  Bernoulli,
  tree depth'=3,
  success name=R,
  miss name=E,
  miss probability=q
  []
\end{forest}

This shows the effect of mixing default settings (not specified) with custom values for some keys.

\bernoullitree

produces a tree with the default settings (which could be changed globally, if required, of course, either by editing my defaults or later changing them with \forestset).

The third tree shows the effect of passing a range of custom values to the macro \bernoullitree.

\bernoullitree[tree depth'=3,success name=R, miss name=E, miss probability=q, root style'=draw, miss style=red, success style=blue, miss edge style={red, densely dashed}, success edge style=blue]

Finally, the last example shows that the direction of growth may be easily modified, should you require a south-growing tree, say, rather than one headed in a westwards direction.

\bernoullitree[before typesetting nodes={for tree={grow'=-90, tier/.option=level}},miss label=above]

sample selection of Bernoulli trees

Complete code:

\documentclass[border=10pt]{standalone}
\usepackage{forest}
\forestset{
  declare toks register={success name},
  declare toks register={miss name},
  declare toks register={success probability},
  declare toks register={miss probability},
  declare count register={tree depth},
  declare keylist register={success style},
  declare keylist register={miss style},
  declare keylist register={root style},
  declare keylist register={miss edge style},
  declare keylist register={success edge style},
  declare toks register={success label},
  declare toks register={miss label},
  tree depth'=4,
  success name=S,
  miss name=M,
  success probability=p,
  miss probability=1-p,
  success style={circle, draw},
  miss style={circle, draw},
  success edge style={},
  miss edge style={},
  root style={circle, fill, draw},
  success label=above,
  miss label=below,
  bernoulli label/.style={
    edge label/.process={RRw2{#1 probability}{#1 label}{node [midway, sloped, ##2] {$##1$}}},
  },
  Bernoulli/.style={
    delay={
      \forestregister{root style},
      tempcounta'=0,
      do while={
        >RR<{tempcounta}{tree depth}
      }{
        where n children=0{append={[,content/.register=miss name,\forestregister{miss style},edge+/.register=miss edge style,bernoulli label=miss,]},prepend={[,content/.register=success name,\forestregister{success style},edge+/.register=success edge style,bernoulli label=success,]}}{},
        do dynamics,
        tempcounta/.max={>O{level}}{tree},
      }
    },
    before typesetting nodes={
      for tree={
        grow'=0,
        math content,
        l sep'+=15pt,
        s sep'+=5pt,
      },
    },
  },
}
\newcommand\bernoullitree[1][]{\begin{forest}Bernoulli,#1[]\end{forest}}

\begin{document}

\begin{forest}
  Bernoulli,
  tree depth'=3,
  success name=R,
  miss name=E,
  miss probability=q
  []
\end{forest}
\bernoullitree
\bernoullitree[tree depth'=3,success name=R, miss name=E, miss probability=q, root style'=draw, miss style=red, success style=blue, miss edge style={red, densely dashed}, success edge style=blue]
\bernoullitree[before typesetting nodes={for tree={grow'=-90, tier/.option=level}},miss label=above]

\end{document}

Tags:

Tikz Pgf