7

I have been trying several things for a while but I am unable to find a working solution.

Let's say I have this pretty simple tree built using the forest package:

\documentclass[border=10pt,multi,tikz]{standalone}
\usepackage{forest}
\begin{document}
\begin{forest}
for tree={circle,draw,s sep=0.8cm}
[$\lambda$
    [,{edge label={node[midway,left] {B}}},{text=white,fill=black}
        [,{edge label={node[midway,left] {A}}}
            [,{edge label={node[midway,left] {B}}}
                [,{edge label={node[midway,left] {A}}},
                {text=white,fill=black}]
            ]
        ]
    ]
    [,{edge label={node[midway,right] {A}}}
        [,{edge label={node[midway,right] {B}}},
            {text=white,fill=black}
            [,{edge label={node[midway,right] {A}}},
            {text=white,fill=black}]
        ]
    ]
]
\end{forest}
\end{document}

It looks like this:

Tree 1

I would like to draw a backwards arrow between two nodes in separate branches. Is it even possible using the forest package (because it technically won't be a tree anymore)?

Tree 2

(Sorry about my English.)

  • Please always post code we can compile (or can try to compile if you want help solving a compilation error) as it makes things much clearer and easier! (That is, you are more likely to get more and higher quality answers this way.) – cfr Oct 21 '16 at 22:28
7

You can give a name to the nodes and then use regular TikZ drawing commands to connect them. You need to wrap the TikZ commands in braces to protect them from the forest bracket parser:

\documentclass{article}
\usepackage{forest}
\begin{document}
\begin{forest}
for tree={circle,draw,s sep=0.8cm}
[$\lambda$
    [,{edge label={node[midway,left] {B}}},{text=white,fill=black}
        [,{edge label={node[midway,left] {A}}}
            [,{edge label={node[midway,left] {B}}}
                [,name=A2,{edge label={node[midway,left] {A}}},
                {text=white,fill=black}]
            ]
        ]
    ]
    [,name=A1,{edge label={node[midway,right] {A}}}
        [,{edge label={node[midway,right] {B}}},
            {text=white,fill=black}
            [,{edge label={node[midway,right] {A}}},
            {text=white,fill=black}]
        ]{\draw[->] (A2) .. controls +(right:1) and +(left:1) .. (A1);}
    ]
]
\end{forest}
\end{document}

output of code

  • @waran Too much typing! (+1 obviously) – cfr Oct 21 '16 at 22:22
6

Here's an adaptation of Alan Munn's answer which may be of interest if you don't like typing or need to draw lots of trees in this style.

I define the the tree styles labelled tree and circle tree for use in the preamble of trees.

labelled tree activates a style which allows you to specify

<content>:<edge label>

as the node's content and have the edge label automatically positioned to the left or the right.

circle tree just makes the nodes circles etc.

In addition, inverse sets the text to white and the fill to black.

Finally, arrow to is a style which takes three arguments.

arrow to={<first control point>}{<second control point>}{<node to connect to>}

This allows you to specify the connector as an option to the node from which the connection should be drawn. The node to connect to may be specified either using a relative node name (e.g. !r2 in this example) or using a label specified with name (as in Alan's answer).

This means that we can draw Alan's tree using the following code.

\begin{forest}
  labelled tree,
  circle tree,
  [$\lambda$
    [:B, inverse
      [:A
        [:B
          [:A, inverse, arrow to={right:1}{left:1}{!r2}
          ]
        ]
      ]
    ]
    [:A
      [:B, inverse
        [:A, inverse
        ]
      ]
    ]
  ]
\end{forest}

labelled circle tree

More generally,

\begin{forest}
  labelled tree,
  circle tree,
  [$\lambda$
    [:B, inverse
      [:A
        [:B
          [:A, inverse, arrow to={right:1}{left:1}{!r2}
          ]
        ]
      ]
    ]
    [:A
      [:B, inverse
        [:A, inverse
        ]
      ]
    ]
  ]
\end{forest}
\begin{forest}
  labelled tree,
  circle tree,
  [$\lambda$
    [:B, inverse
      [:A
        [:B
          [:A, inverse, arrow to={left:1}{left:1}{!r1}
          ]
        ]
      ]
    ]
  ]
\end{forest}
\begin{forest}
  labelled tree,
  circle tree,
  [$\lambda$
    [:B, inverse
      [:A
        [:B
          [:A, inverse, arrow to={right:1}{left:1}{!r2}
          ]
        ]
      ]
    ]
    [:A
      [:B, inverse
        [:A, inverse
        ]
      ]
    ]
    [:B
      [:A, inverse
        [:B
          [:A, inverse, arrow to={left:1}{right:1}{!r2}
          ]
        ]
      ]
    ]
  ]
\end{forest}
\begin{forest}
  labelled tree,
  circle tree,
  [$\lambda$
    [$\omega$
      [:B, inverse
        [:A
          [:B
            [:A
              [:B, inverse, arrow to={right:1}{left:1}{!uuu2}
              ]
            ]
          ]
          [:A
             [:B
              [:A, inverse, arrow to={right:1}{left:1}{!r12}
              ]
            ]
          ]
        ]
      ]
      [:A
        [:B, inverse
          [:A, inverse
          ]
        ]
      ]
      [:B
        [:A, inverse
          [:B
            [:A, inverse, arrow to={left:1}{right:1}{!r12}
            ]
          ]
        ]
      ]
    ]
  ]
\end{forest}

produces

generalised case

Complete code:

\documentclass[border=10pt]{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},
      },
    },
  },
  arrow to/.style n args=3{
    tikz+={
      \draw [->] () .. controls +(#1) and +(#2) .. (#3);
    }
  },
  inverse/.style={text=white, fill=black},
  circle tree/.style={
    for tree={
      circle,
      draw,
      s sep=0.8cm,
      edge={->},
    },
  }
}
\begin{document}
\begin{forest}
  labelled tree,
  circle tree,
  [$\lambda$
    [:B, inverse
      [:A
        [:B
          [:A, inverse, arrow to={right:1}{left:1}{!r2}
          ]
        ]
      ]
    ]
    [:A
      [:B, inverse
        [:A, inverse
        ]
      ]
    ]
  ]
\end{forest}
\begin{forest}
  labelled tree,
  circle tree,
  [$\lambda$
    [:B, inverse
      [:A
        [:B
          [:A, inverse, arrow to={left:1}{left:1}{!r1}
          ]
        ]
      ]
    ]
  ]
\end{forest}
\begin{forest}
  labelled tree,
  circle tree,
  [$\lambda$
    [:B, inverse
      [:A
        [:B
          [:A, inverse, arrow to={right:1}{left:1}{!r2}
          ]
        ]
      ]
    ]
    [:A
      [:B, inverse
        [:A, inverse
        ]
      ]
    ]
    [:B
      [:A, inverse
        [:B
          [:A, inverse, arrow to={left:1}{right:1}{!r2}
          ]
        ]
      ]
    ]
  ]
\end{forest}
\begin{forest}
  labelled tree,
  circle tree,
  [$\lambda$
    [$\omega$
      [:B, inverse
        [:A
          [:B
            [:A
              [:B, inverse, arrow to={right:1}{left:1}{!uuu2}
              ]
            ]
          ]
          [:A
             [:B
              [:A, inverse, arrow to={right:1}{left:1}{!r12}
              ]
            ]
          ]
        ]
      ]
      [:A
        [:B, inverse
          [:A, inverse
          ]
        ]
      ]
      [:B
        [:A, inverse
          [:B
            [:A, inverse, arrow to={left:1}{right:1}{!r12}
            ]
          ]
        ]
      ]
    ]
  ]
\end{forest}
\end{document}
  • I bow to your superior forest fu. :) – Alan Munn Oct 21 '16 at 22:35
  • @AlanMunn I'm a fiddler .... Please see edited answer above. – cfr Oct 22 '16 at 0:15
  • @waran If you use this, please note that I've updated the code above to make it a bit more robust. – cfr Oct 23 '16 at 23:12
  • Thank you. :) I have used the original answer by Alan Munn, because it was easier for me to implement into existing code. But I am pretty sure that I will need to do something similar in some point and I will probably use your solution, because it's more synoptic for larger graphs. :) – janjaromirhorak Oct 24 '16 at 6:26

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.