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).

  • Do you want to have also only above and only below? – Alenanno Jun 21 '15 at 22:31
  • Yes, I would like the flexibility to have above, below, both, or none. – fraserbc Jun 21 '15 at 23:02
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

  • Thank you! Great solution, including the help on spacing. – fraserbc Jun 22 '15 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 '15 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}
  • @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 '15 at 23:17
  • @cfr Oh that stuck around. I'll remove it. – Alenanno Jun 21 '15 at 23:18
  • Actually, I see the text width is in the original code in the question.... – cfr Jun 21 '15 at 23:18
  • @cfr Yes, but with it the labels are not properly centered. – Alenanno Jun 21 '15 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 '15 at 23:24

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.