5

I am trying to generate a decision tree similar to this scanned example:

enter image description here

Notice that some branches have text on the top as well as the bottom. I have not figured out how to do this. I can get text on the top or bottom, but not both.

I am enclosing a partial solution. I try to Add "Outbreak" as the top label and "0.060" as the bottom label, but it causes the first label to disappear.

   \documentclass{beamer}

\usepackage{tikz}
\usetikzlibrary{trees,shapes,snakes}
\usepackage{forest}


\tikzset{
    decision/.style={rectangle, minimum height=10pt, minimum width=10pt, draw=black, fill=black!30!white, thick, inner sep=0pt},
    chance/.style={circle, minimum width=10pt, draw=black, fill=black!30!white, thick, inner sep=0pt},
    leaf-chance/.style={isosceles triangle, minimum width=10pt, draw=black, thick, fill=white, inner sep=0pt, shape border rotate=180, outer sep=-\pgflinewidth}
  }

\newsavebox\notgood
\sbox\notgood{\textbardbl}
\forestset{
  declare toks={optimality}{},
  sub optimal/.style={
    optimality={
      node [midway, sloped] {\usebox\notgood}
    }
  }
}

\begin{document}


\begin{frame}[fragile]

\scalebox{0.85}{
 \begin{forest}
   %my label/.style={
   %   edge label={node[auto, sloped,pos=.75,anchor=south]{#1}}
   % },
   my label/.style={
     edge label={node[midway,above,font=\scriptsize,text width=1.5cm,align=center]{#1}}
   },
   my below/.style={
     edge label={node[midway,below,font=\scriptsize,text width=1.5cm,align=center]{#1}}
     },
    for tree={
      grow=0,
      child anchor=west,
      anchor=west,
      text ragged,
      inner sep=1mm,
      edge={thick, draw=blue},
      l sep+=30mm,
      s sep+=5mm,
      if n children=0{
        before typesetting nodes={
          label/.wrap pgfmath arg={right:#1}{content()},
          content={},
          leaf-chance,
        },
      }{},
      edge path={
        \noexpand\path[\forestoption{edge}]
       (!u.parent anchor) -- ([xshift=-22.5mm].child anchor)\forestove{optimality} --  (.child anchor)\forestoption{edge label};
  },
    }
    [,decision
      [0.8351,chance,my label=Insure]
      [,chance,my label=Don't Insure, sub optimal      
        [0.8394,chance,my label=No outbreak
        ]
        [,chance,my label=Outbreak, my below=0.060
          [0.8334,chance,my label=Bans only
          ]
          [0.6663,chance,my label=Slaughter
          ]
        ]
      ]
    ]
\end{forest}
}

\end{frame}
\end{document}

enter image description here

I found this previous answer helpful in switching between above/below, but doesn't show how to get both: https://tex.stackexchange.com/a/177254/80455

Also, this is the same example as Adding Short Lines Across Decision Tree Branch (but a different question).

2
  • Do you want to have also only above and only below?
    – Alenanno
    Jun 21, 2015 at 22:31
  • Yes, I would like the flexibility to have above, below, both, or none.
    – fraserbc
    Jun 21, 2015 at 23:02

2 Answers 2

5

edge label will override any previous value for any particular node. So the first label disappears. But we can use the same method as I used for the sub optimal style i.e. declare another option, just like edge label and then add it to the redefinition of edge path.

\documentclass{beamer}

\usepackage{etex,forest}
\usetikzlibrary{shapes,snakes}


\tikzset{
    decision/.style={rectangle, minimum height=10pt, minimum width=10pt, draw=black, fill=black!30!white, thick, inner sep=0pt},
    chance/.style={circle, minimum width=10pt, draw=black, fill=black!30!white, thick, inner sep=0pt},
    leaf-chance/.style={isosceles triangle, minimum width=10pt, draw=black, thick, fill=white, inner sep=0pt, shape border rotate=180, outer sep=-\pgflinewidth}
  }

\newsavebox\notgood
\sbox\notgood{\textbardbl}
\forestset{
  declare toks={optimality}{},
  sub optimal/.style={
    optimality={
      node [midway, sloped] {\usebox\notgood}
    }
  },
  declare toks={edge label below}{},
}

\begin{document}


\begin{frame}[fragile]
\scalebox{0.85}{%
 \begin{forest}
   my label/.style={
     edge label={node[midway,above,font=\scriptsize,text width=1.5cm,align=center]{#1}}
   },
  my below/.style={
    edge label below={node[midway,below,font=\scriptsize,text width=1.5cm,align=center]{#1}}
  },
    for tree={
      grow=0,
      child anchor=west,
      anchor=west,
      text ragged,
      inner sep=1mm,
      edge={thick, draw=blue},
      l sep+=30mm,
      s sep+=5mm,
      if n children=0{
        before typesetting nodes={
          label/.wrap pgfmath arg={right:#1}{content()},
          content={},
          leaf-chance,
        },
      }{},
      edge path={
        \noexpand\path[\forestoption{edge}]
        (!u.parent anchor) -- ([xshift=-22.5mm].child anchor)\forestove{optimality} --  (.child anchor)\forestoption{edge label below}\forestoption{edge label};
  },
    }
    [,decision
      [0.8351,chance,my label=Insure]
      [,chance,my label=Don't Insure, sub optimal
        [0.8394,chance,my label=No outbreak
        ]
        [,chance,my label=Outbreak, my below=0.060
          [0.8334,chance,my label=Bans only
          ]
          [0.6663,chance,my label=Slaughter
          ]
        ]
      ]
    ]
\end{forest}%
}%
\end{frame}
\end{document}

edge labels above and below

To avoid the crowding, either allow longer labels (increase or remove text width) or increase the value of s sep.

Removing the restriction on text width:

   my label/.style={
     edge label={node[midway,above,font=\scriptsize,align=center]{#1}}
   },
  my below/.style={
    edge label below={node[midway,below,font=\scriptsize,align=center]{#1}}
  },

longer labels

Increasing s sep:

  s sep+=7.5mm,

more distant siblings

2
  • Thank you! Great solution, including the help on spacing.
    – fraserbc
    Jun 22, 2015 at 2:35
  • @fraserbc I'm somewhat obsessed with forest ;). After I finally figured out how to use it (with some help from this site).
    – cfr
    Jun 22, 2015 at 2:46
3

This is a bit of a "hack", but you can simply set an extra label without the above or below keys. Then using \\ when you want to switch to the "other line", they will show one above, one below.

So basically, you'll have:

  • my above
  • my below
  • my label (both)

As far as you've showed, this will work. If there is some situation where this behaviour breaks, please specify it.

Output

figure 1

Code

\documentclass{beamer}   
\usepackage{tikz}
\usetikzlibrary{trees,shapes,snakes}
\usepackage{forest}


\tikzset{
    decision/.style={rectangle, minimum height=10pt, minimum width=10pt, draw=black, fill=black!30!white, thick, inner sep=0pt},
    chance/.style={circle, minimum width=10pt, draw=black, fill=black!30!white, thick, inner sep=0pt},
    leaf-chance/.style={isosceles triangle, minimum width=10pt, draw=black, thick, fill=white, inner sep=0pt, shape border rotate=180, outer sep=-\pgflinewidth}
  }

\newsavebox\notgood
\sbox\notgood{\textbardbl}
\forestset{
  declare toks={optimality}{},
  sub optimal/.style={
    optimality={
      node [midway, sloped] {\usebox\notgood}
    }
  }
}

\begin{document}


\begin{frame}[fragile]

\scalebox{0.85}{
 \begin{forest}
    my above/.style={
        edge label={node[midway,above,font=\scriptsize,align=center]{#1}}
    },
    my below/.style={
        edge label={node[midway,below,font=\scriptsize,align=center]{#1}}
    },
    my label/.style={
        edge label={node[midway,font=\scriptsize,align=center]{#1}}
    },
    for tree={
      grow=0,
      child anchor=west,
      anchor=west,
      text ragged,
      inner sep=1mm,
      edge={thick, draw=blue},
      l sep+=30mm,
      s sep+=5mm,
      if n children=0{
        before typesetting nodes={
          label/.wrap pgfmath arg={right:#1}{content()},
          content={},
          leaf-chance,
        },
      }{},
      edge path={
        \noexpand\path[\forestoption{edge}]
       (!u.parent anchor) -- ([xshift=-22.5mm].child anchor)\forestove{optimality} --  (.child anchor)\forestoption{edge label};
  },
    }
    [,decision
      [0.8351,chance,my above=Insure]
      [,chance,my below=Don't Insure, sub optimal      
        [0.8394,chance,my above=No outbreak
        ]
        [,chance,my label=Outbreak\\0.060
          [0.8334,chance,my above=Bans only
          ]
          [0.6663,chance,my below=Slaughter
          ]
        ]
      ]
    ]
\end{forest}
}
\end{frame}
\end{document}
6
  • @cfr It will go on. But then the diagram would be badly constructed if you need a label that long for a small path. I'd redesign the diagram.
    – Alenanno
    Jun 21, 2015 at 23:17
  • @cfr Oh that stuck around. I'll remove it.
    – Alenanno
    Jun 21, 2015 at 23:18
  • Actually, I see the text width is in the original code in the question....
    – cfr
    Jun 21, 2015 at 23:18
  • @cfr Yes, but with it the labels are not properly centered.
    – Alenanno
    Jun 21, 2015 at 23:19
  • (+1) I think it is better without, too. [I'm not sure if I'm the one who introduced them in the first place!]
    – cfr
    Jun 21, 2015 at 23:24

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .