4

I have the following code

\documentclass{article}
\usepackage{tikz}
\usepackage{tikz-qtree}
\begin{document}
\begin{tikzpicture}
\tikzset{grow'=right, level distance=32pt}
\tikzset{execute at begin node=\strut}
\tikzset{every tree node/.style={anchor=base west}}
\Tree [ [.J [.J ] [.S ] ]
[.S [.J ]
[.S ] ] ] ]
\end{tikzpicture}
\end{document}

Which gives me the following:

enter image description here

I, however, want to get it to look something as follows:

enter image description here

How can I adapt my code in order to have the labels alongside the edges?

6

It is a tree, so I would use Forest. The labelled tree style defined below allows you to write each node in the form

<content>:<label for edge>

and the code should automatically figure out what to do and where to position the label.

For example, we can write:

\begin{forest}
  for tree={
    grow'=0,
    parent anchor=children,
    child anchor=parent,
    l sep'+=20pt,
  },
  delay={
    where content={}{}{
      content/.wrap value={\strut #1},
    },
  },
  labelled tree,
  sloped labels,
  [
    [J:0.3
      [J:0.3]
      [S:0.7]
    ]
    [S:0.7
      [J:0.3]
      [S:0.7]
    ]
  ]
\end{forest}

to produce

semi-auto-labelled tree

Complete code for labelled tree:

\documentclass[border=10pt,multi,tikz]{standalone}
\usepackage{forest}
\forestset{
  declare boolean register=sloped labels,
  not sloped labels,
  my edge label/.style={
    tempcountc/.option=grow,
    if reversed={
      tempcountc-/.register=tempcountb,
    }{
      tempcountc+/.register=tempcountb,
    },
    if sloped labels={
      temptoksa=sloped,
    }{
      temptoksa=,
    },
    edge label/.expanded={node [midway, shift=(\foresteregister{tempcountc}:10pt), \foresteregister{temptoksa}] {#1}}
  },
  labelled tree/.style={
    before typesetting nodes={
      where={(n_children())>1}{
        tempcounta/.pgfmath={int(((n_children())+1)/2)},
        if={isodd(n_children())}{
          for n/.wrap pgfmath arg={{##1}{calign with current}}{(tempcounta)},
        }{},
        for nodewalk={
          n=1,
          filter={current and siblings}{n()<(tempcounta)},
        }{
          for nodewalk={
            c,
            while={int(n_children())==1}{
              on invalid={fake}{n=1},
            }{},
          }{
            tempcountb'=-90,
            split option={content}{:}{content,my edge label},
          },
        },
        for nodewalk={
          n'=1,
          filter={current and siblings}{n()>=(tempcounta)},
        }{
          for nodewalk={
            c,
            while={int(n_children())==1}{
              on invalid={fake}{n=1},
            }{},
          }{
            tempcountb'=-270,
            split option={content}{:}{content,my edge label},
          },
        },
      }{},
      for nodewalk={
        fake=r,
        while={int(n_children())==1}{
          on invalid={fake}{n=1},
        }{},
      }{
        tempcountb'=-270,
        split option={content}{:}{content,my edge label},
      },
    },
  },
}
\begin{document}
\begin{forest}
  for tree={
    grow'=0,
    parent anchor=children,
    child anchor=parent,
    l sep'+=20pt,
  },
  delay={
    where content={}{}{
      content/.wrap value={\strut #1},
    },
  },
  labelled tree,
  sloped labels,
  [
    [J:0.3
      [J:0.3]
      [S:0.7]
    ]
    [S:0.7
      [J:0.3]
      [S:0.7]
    ]
  ]
\end{forest}
\end{document}

However, if your trees follow the structure illustrated by the one in the question, you might not want to bother adding the content and labels for each node since these are always the same.

In that case, you might be interested in a recursive tree style which adds these automatically. To specify the labels and node contents simply write,

recursive tree,
first option=<content>:<probability>,
second option=<content>:<probability>,

in the tree's preamble. For example,

\begin{forest}
  for tree={
    grow'=0,
    l sep'+=20pt,
  },
  recursive tree,
  first option=S:0.7,
  second option=J:0.3,
  [
    [
      []
      []
    ]
    [
      []
      []
    ]
  ]
\end{forest}

produces output identical to that above.

Even this seems unnecessarily verbose. It would be nice if we could tell Forest how many recursions to implement and let the style do the rest. We can do this using the key

recur=<integer>,

which will add <integer> levels below (or to the right of) the root. That is,

\begin{forest}
  before packing={
    for tree={
      grow'=0,
      l sep'+=20pt,
    },
  },
  recursive tree,
  first option=S:0.7,
  second option=J:0.3,
  recur'=2,
  [
  ]
\end{forest}

will create the same output as that shown above. Moreover,

\begin{forest}
  before packing={
    for tree={
      grow'=0,
      l sep'+=20pt,
    },
  },
  recursive tree,
  first option=Health:0.89,
  second option=Disease:0.11,
  recur'=5,
  [
  ]
\end{forest}

will produce

automatically constructed and labelled tree

which is is a lot of tree for relatively little code!

Complete code for recursive tree:

\documentclass[border=10pt,tikz]{standalone}
\usepackage{forest}
\forestset{
  declare boolean register=sloped labels,
  not sloped labels,
  declare toks register=first option,
  first option=A:0.5,
  declare toks register=second option,
  second option=B:0.5,
  declare toks register=first option name,
  declare toks register=second option name,
  declare toks register=first option probability,
  declare toks register=second option probability,
  first option name=first,
  second option name=second,
  first option probability=1,
  second option probability=0,
  declare count register=recur,
  recur'=0,
  my edge label/.style={
    tempcountc/.option=grow,
    if reversed={
      tempcountc-/.register=tempcountb,
    }{
      tempcountc+/.register=tempcountb,
    },
    if sloped labels={
      temptoksa=sloped,
    }{
      temptoksa=,
    },
    edge label/.expanded={node [midway, shift=(\foresteregister{tempcountc}:10pt), \foresteregister{temptoksa}] {#1}}
  },
  recursive tree/.style={
    sloped labels,
    before typesetting nodes={
      split register={first option}{:}{first option name,first option probability},
      split register={second option}{:}{second option name,second option probability},
      where n=1{
        content/.register=first option name,
        before packing={
          tempcountb'=-90,
          my edge label/.register=first option probability,
        },
      }{
        if n'=1{
          content/.register=second option name,
          before packing={
            tempcountb'=-270,
            my edge label/.register=second option probability,
          },
        }{}
      },
      for tree={
        parent anchor=children,
        child anchor=parent,
      },
    },
    delay={
      if recur=0{}{
        tempcountd'=1,
        repeat={(recur)}{
          delay n/.wrap pgfmath arg={%
            {####1}{
              where n children=0{
                append={[]},
                prepend={[]},
              }{},
            }%
          }{(tempcountd)},
          tempcountd+=1,
        },
      },
    },
  },
}
\begin{document}
\begin{forest}
  for tree={
    grow'=0,
    l sep'+=20pt,
  },
  recursive tree,
  first option=S:0.7,
  second option=J:0.3,
  [
    [
      []
      []
    ]
    [
      []
      []
    ]
  ]
\end{forest}
\begin{forest}
  before packing={
    for tree={
      grow'=0,
      l sep'+=20pt,
    },
  },
  recursive tree,
  first option=S:0.7,
  second option=J:0.3,
  recur'=2,
  [
  ]
\end{forest}
\begin{forest}
  before packing={
    for tree={
      grow'=0,
      l sep'+=20pt,
    },
  },
  recursive tree,
  first option=Health:0.89,
  second option=Disease:0.11,
  recur'=5,
  [
  ]
\end{forest}
\end{document}
5

The annotations can be inserted by \edge commands, see section "5 Explicit edges" of tikz-qtree, e.g.:

\documentclass{article}
\usepackage{tikz}
\usepackage{tikz-qtree}
\begin{document}
\begin{tikzpicture}
\tikzset{grow'=right, level distance=32pt}
\tikzset{execute at begin node=\strut}
\tikzset{every tree node/.style={anchor=base west}}
\Tree [
  \edge node[above]{.3};
  [.J
    \edge node[above]{.3}; [.J ]
    \edge node[below]{.7}; [.S ]
  ]
  \edge node[below]{.7};
  [.S
    \edge node[above]{.3}; [.J ]
    \edge node[below]{.7}; [.S ]
  ]
]
\end{tikzpicture}
\end{document}

Result

A little more compact representation, both in source and result:

\documentclass{article}
\usepackage{tikz-qtree}
\begin{document}
\begin{tikzpicture}[
  grow'=right, level distance=32pt,
  J/.style={above=.2em, node contents={.3}},
  S/.style={below=.2em, node contents={.7}},
]
\Tree [
  \edge node[J]; [.J
    \edge node[J]; [.J ]
    \edge node[S]; [.S ]
  ]
  \edge node[S]; [.S
    \edge node[J]; [.J ]
    \edge node[S]; [.S ]
  ]
]
\end{tikzpicture}
\end{document}

Compact result

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.