2

I'm trying to replicate the following tree using forest.

enter image description here

And here's what I got

enter image description here

Aside from the slightly misplaced labels Pass, which I can tweak by passing elo={xshift=<n>pt,yshift=<n>pt to the relevant branches, I'm more interested in getting the directions/angles of the branches right.

Ideally, I'd like

  • the Take branches to all grow at -90 degrees (not slightly more, and non-parallel, as they currently are), and
  • the Pass branches to grow at 0 degree (I'm now able to get this by manually putting before computing xy={l=0,s=15mm} to everyone of them, a solution given in this answer, but I'd like to know a less cumbersome solution if one exists).

MWE

\documentclass[border=2pt]{standalone}
\usepackage{forest}
\forestset{
  declare toks={elo}{}, % Edge Label Options
  anchors/.style={anchor=#1,child anchor=#1,parent anchor=#1},
  dot/.style={tikz={\draw[#1] (.child anchor) circle[radius=1.5pt];}},
  decision edge label/.style n args=3{
    edge label/.expanded={node[midway,auto=#1,anchor=#2,\forestoption{elo}]{\strut\unexpanded{#3}}}
  },
  decision/.style={if n=1
    {decision edge label={left}{east}{#1}}
    {decision edge label={right}{west}{#1}}
  },
  game tree/.style={
    for tree={
      s sep=0mm,l=15mm,
      if n children=0{anchors=north}{
        if n=1{anchors=south east}{anchors=south west}},
      math content,
      /tikz/font=\footnotesize,
    },
    anchors=south, 
    dot={fill=white},for descendants={dot={fill}},
    delay={for descendants={split option={content}{;}{decision,content}}},
  },
}
\begin{document}
\begin{forest}
  game tree
  [A,
    [Take;{(4,2)},]
    [Pass;B,before computing xy={l=0,s=15mm},elo={xshift=-10pt,yshift=5pt}
      [Take;{(2,8)}]
      [Pass;A,before computing xy={l=0,s=15mm} 
        [Take;{(16,4)}]
        [Pass;B,before computing xy={l=0,s=15mm}
          [Take;{(8,32)}]
          [Pass;{(64,16)},before computing xy={l=0,s=15mm}]
        ]
      ]
    ]
  ]
\end{forest}
\end{document}

Edit

After some fooling around, I managed to get the angles right (by basically specifying before computing xy for every branch). But the way I did it seemed so excessively hackish that it almost made forest lose its appeal: automatic positioning nodes to avoid overlaps. I could've drawn the tree in TikZ with this amount of code.

\begin{forest}
  game tree
  [A,
    [Take;{(4,2)},before computing xy={l=15mm,s=0mm}]
    [Pass;B,before computing xy={l=0,s=15mm},elo={xshift=-10pt,yshift=5pt},anchors=south
      [Take;{(2,8)},before computing xy={l=15mm,s=0mm}]
      [Pass;A,before computing xy={l=0,s=15mm},elo={xshift=-10pt,yshift=5pt},anchors=south 
        [Take;{(16,4)},before computing xy={l=15mm,s=0mm}]
        [Pass;B,before computing xy={l=0,s=15mm},elo={xshift=-10pt,yshift=5pt},anchors=south
          [Take;{(8,32)},before computing xy={l=15mm,s=0mm}]
          [Pass;{(64,16)},before computing xy={l=0,s=15mm},elo={xshift=-10pt,yshift=5pt}]
        ]
      ]
    ]
  ]
\end{forest}

enter image description here

I'm still looking for a more efficient way to accomplish this.

  • Is the forest right tool for this relatively simple image? I'm pretty sure that drawing with pure tikz is far simpler. – Zarko Mar 10 '17 at 20:32
  • @Zarko: For this particular one, TikZ is probably the better choice. However, I draw a lot of trees for my documents and forest (with the setting in the preamble of my MWE) is the most efficient way for the majority of them. So I'd prefer not to leave the forest framework if there is a better way to do this. – Herr K. Mar 10 '17 at 20:37
  • @Zarko I don't see why. – cfr Mar 10 '17 at 20:58
  • @HerrK. I think you are making life unduly difficult for yourself :-). If you try to do everything with manual adjustments, then it is going to get more complicated than using TikZ, but I don't think you need these at all. – cfr Mar 10 '17 at 21:00
  • @cfr, because I'm not so skilled in use of forest as you are :) and complexity of OP MWE scare me :-(. – Zarko Mar 10 '17 at 21:50
3

This is possibly not the very most efficient method, but it is probably better than placing everything manually.

The key idea is to specify the tree's direction of growth in a way which reflects the intended result, rather than letting it grow in some inappropriate direction and later having to override it.

For this reason, it makes sense to specify the angle of growth as -45.

We basically want each child to be +/-45 degrees from the direction of growth. This will put the edges at 0 and -90. And we want these angles fixed, so we need calign=fixed edge angles as our placement strategy.

We then delete all of the manual placement stuff to let Forest do its thing and just need to adjust the placement of the edge labels appropriately.

In this kind of case, it is also easier, if there's no compelling reason not to do it, to turn the content of the nodes into label options and turn the nodes into filled circles. This saves needing to use tikz to draw the circles.

To treat the root node along with the rest, we can change the content to ;A. We also need to specify maths for the labels because these are no longer covered by math content. In fact, math content would now do nothing as the nodes proper don't contain any content at all: it is all split out into either edge labels or labels.

If you have large and variously sized nodes, it would be better not to turn the content into labels. However, in this tree, the content is small, compact and relatively consistent: the paired values go below anyway, where they have plenty of room, and the remaining are single letters which can be easily accommodated. If your real tree is not like this, let me know and I can modify the answer to avoid use of label.

\documentclass[border=10pt,multi,tikz]{standalone}
\usepackage{forest}
\forestset{
  decision edge label/.style n args=3{
    edge label/.expanded={
      node [midway, #1, anchor=#2] {\strut\unexpanded{#3}}
    },
  },
  decision/.style={
    if n=1{% Take
      decision edge label={left}{east}{#1},
    }{% Pass
      decision edge label={above}{south}{#1},
    }
  },
  game tree/.style={
    for tree={
      /tikz/font=\footnotesize,
      grow=-45,
      calign angle=45,
      calign=fixed edge angles,
    },
    before typesetting nodes={
      for tree={
        split option={content}{;}{decision,node label},
        delay={
          content=,
          circle,
          draw,
          if level=0{fill=white}{fill},
          inner sep=1.5pt,
        },
      },
    },
  },
  node label/.style={
    if={
      > O_= O_= | {n}{1}{n children}{0}%
    }{
      label=below:{$#1$},
    }{
      label=above:{$#1$},
    },
  },
}
\begin{document}
\begin{forest}
  game tree,
  [;A,
    [Take;{(4,2)},]
    [Pass;B
      [Take;{(2,8)}]
      [Pass;A
        [Take;{(16,4)}]
        [Pass;B
          [Take;{(8,32)}]
          [Pass;{(64,16)}]
        ]
      ]
    ]
  ]
\end{forest}
\end{document}

auto layout for tree with fixed edge angles and south-easterly growth

  • Thanks for the detailed explanation and elegant solution! – Herr K. Mar 10 '17 at 21:09
  • interesting solution! Good trick with combination of grow and calign angles! I need to read forest manual (section 3.7.2) again ... – Zarko Mar 10 '17 at 21:56
2

Another solution with istgame package. You can control the direction of tree growing like \setistgrowdirection{-45}.

enter image description here

\documentclass{standalone}

\usepackage{istgame}

\begin{document}    
\begin{istgame}[font=\footnotesize]
\setistgrowdirection{-45}
\xtdistance{15mm}{30mm}
\istroot(0)[initial node]{A}
  \istb{Take}[l]{4,2}[b]
  \istb{Pass}[a]
  \endist
\istroot(1)(0-2){B}
  \istb{Take}[l]{2,8}[b]
  \istb{Pass}[a]
  \endist
\istroot(2)(1-2){A}
  \istb{Take}[l]{16,4}[b]
  \istb{Pass}[a]
  \endist
\istroot(3)(2-2){B}
  \istb{Take}[l]{8,32}[b]
  \istb{Pass}[a]{64,16}[r]
  \endist
\end{istgame}

\end{document}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.