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

1
  • 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, 2016 at 22:28

2 Answers 2

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

1
  • @waran Too much typing! (+1 obviously)
    – cfr
    Oct 21, 2016 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}
4
  • 1
    I bow to your superior forest fu. :)
    – Alan Munn
    Oct 21, 2016 at 22:35
  • @AlanMunn I'm a fiddler .... Please see edited answer above.
    – cfr
    Oct 22, 2016 at 0:15
  • 1
    @waran If you use this, please note that I've updated the code above to make it a bit more robust.
    – cfr
    Oct 23, 2016 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. :)
    – jenda
    Oct 24, 2016 at 6:26

You must log in to answer this question.

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