0

I would like to be able to add an optional diamond and a 'curvy arrow' in the below diagram. I was thinking of trying to put tikz commnads in the forest environment but that doesn't seem to work. An example would be something like this: enter image description here

    \begin{forest}
        for tree=draw,
        [Main(), [Level Setup],[Game], [Win_Game()]]
    \end{forest}

This is what I have for now, and I noted a code snippet I found with edge label={node[midway,left,font=\scriptsize]{text}}, which would give the labels on the arrows I would want to draw, but do not draw the arrow.

6
  • 1
    Welcome. // Please avoid posting code fragments only from now on: nobody likes to reverse-engineer such code. Standard here is to provide code, which compiles, is minimal AND shows your problem (and own attempts). Thank you (Your fragment did not compile even after good will activities wrt your code ...)
    – MS-SPO
    Dec 3, 2023 at 15:50
  • So sorry. I'll make sure to not do this again. Is there a link to a 'checklist' I can use when asking questions as to be specific?
    – apathyy
    Dec 3, 2023 at 23:05
  • There are some links to useful Meta questions at tex.meta.stackexchange.com/questions/2419/…. However, I thought there would be something more to the point regarding MWEs. One link focuses on reducing code. The other doesn't really deal with the details of what code to post at all. A question should include code I can copy, paste and (try to) compile. If the question is about an error, it should include the error and the code should produce that error; otherwise the code should compile and the question should explain what concrete thing is a problem.
    – cfr
    Dec 4, 2023 at 3:42
  • (Usually. Some questions are conceptual.) You could ask on Meta if there's a checklist. (A concise checklist - not an essay.)
    – cfr
    Dec 4, 2023 at 3:49
  • 1
    Thank you both :)
    – apathyy
    Dec 4, 2023 at 11:28

2 Answers 2

2

Here's a version with some styles you can modify or reuse as required. I started from MS-SPO's code because it compiled.

\documentclass[10pt,border=3mm,tikz]{standalone}
% ateb: https://tex.stackexchange.com/a/703039/ addaswyd o ateb MS-SPO: https://tex.stackexchange.com/a/703008/ i gwestiwn apathyy: https://tex.stackexchange.com/q/702992/
\usepackage{forest}
\usetikzlibrary{arrows.meta,shapes.geometric}    % to modify arrow tips, see ch. 16.5 pfgmanual
\forestset{%
  from diamond/.style={%
    before typesetting nodes={%
      replace by={%
        [,
          diamond, 
          inner sep=1.5pt, 
          no edge, 
          anchor=north, 
          draw, 
          append,
          before drawing tree={%
            y'=0pt,
            if={>Od>{x}{0pt}}{x'=10pt}{x'=-10pt},
          },
        ]%
      },
    },
  },
  branch arrows/.style args={from #1 to #2 with label #3 and from #4 to #5 with label #6}{%
    edge label+/.process={Ow{name}{coordinate [pos=#1] (##1-a) coordinate [pos=#2] (##1-b) coordinate [pos=#4] (##1-c) coordinate [pos=#5] (##1-d)}},
    tikz+/.process={Ow{name}{%
        \draw [{Circle[open]}-Stealth,very thin] (##1-c) ++(0pt,2.5pt) -- ([yshift=2.5pt]##1-d) node [above,my branch arrow label] {#3};
        \draw [{Circle[open]}-Stealth,very thin] (##1-b) ++(0pt,-2.5pt) -- ([yshift=-2.5pt]##1-a) node [below,my branch arrow label] {#6};
      }%
    },
  },
  trunk arrows/.style args={from #1 to #2 with label #3 and from #4 to #5 with label #6}{%
    edge label+/.process={Ow{name}{coordinate [pos=#1] (##1-a) coordinate [pos=#2] (##1-b) coordinate [pos=#4] (##1-c) coordinate [pos=#5] (##1-d)}},
    tikz+/.process={Ow{name}{%
        \draw [{Circle[open]}-Stealth,very thin] (##1-c) ++(2.5pt,0pt) -- ([xshift=2.5pt]##1-d) node [right,my arrow label] {#3};
        \draw [{Circle[open]}-Stealth,very thin] (##1-b) ++(-2.5pt,0pt) -- ([xshift=-2.5pt]##1-a) node [left,my arrow label] {#6};
      }%
    },
  },
  apathyy tree/.style={%
    for tree={%
      draw,
      fit=band,
      s sep'+=20pt,
      delay={content+=\strut},
      font=\sffamily,
    },
    for descendants={anchor=north,
      tier/.option=level,
    },
    anchor=south,
  },
  /tikz/my arrow label/.style={midway,font=\sffamily\tiny,inner sep=1pt,},
  /tikz/my branch arrow label/.style={/tikz/my arrow label,sloped},
}
\begin{document}
\begin{forest}
  apathyy tree,
  [Main()
    [Level Setup, 
      {fill=blue!20}, 
      from diamond,
      branch arrows=from 0.125 to 0.525 with label {text} and from 0.575 to 0.975 with label {other},
      [nested 1
        [nested 1.1]
        [nested 1.2
          [nested 1.2.1
            [nested 1.2.2]
          ]
        ]
      ]
    ]   % just put some color
    [Game,
      calign with current edge,
      trunk arrows=from 0.9 to 0.4 with label {label} and from 0.95 to 0.1 with label {extra},
      [nested 1]
      [nested 2]
    ]       % this tree only with ordinary lines
    [Win\_Game(), 
      from diamond,
      branch arrows=from 0.125 to 0.525 with label {more} and from 0.575 to 0.975 with label {another},
      [nested 1
        [nested 1.1]
      ]
    ]                   % you need to backslash the underscore
  ]
  \draw [-Stealth] (!r1.west) ..controls +(-25pt,-5pt) and +(-5pt,0pt).. ([yshift=-4pt]!r.center |- !r1.south) ..controls +(5pt,0pt) and +(25pt,-5pt).. (!r3.east);
\end{forest}
\end{document}

apathyy tree with arrowed styling

EDIT

Here's a somewhat more flexible version. It doesn't change how you add diamonds etc., but it should do a better job of placing things by default.

more diamonds and arrows

To add a diamond, you just add from diamond to the child, as before.

The curved arrows are just regular TikZ commands added after the tree is drawn. I've added two further examples.

  • The simplest method is just to name the node you want, as I do with wingame.
  • However, this isn't straightforward for the diamonds, so I've used forest node names for those. Basically, the ! indicates a 'walk' through the tree to a node. r is the root. 1 is the first child, 2 the second and so on.
  • So (!r1.west) is the diamond node at the top of the branch leading to the 'Level Setup' node.
  • (!r21.west) is the west anchor of the first child of the second child of the root i.e. the diamond at the start of the branch from 'Game' to 'nested 1'.

Note that the following code uses a custom argument processor because I couldn't get the standard processors to do what I wanted. As far as I know, there is no official way to do this, so the definition uses internal macros. This means you can't blame forest's author if a package update breaks that bit. (You probably should blame me rather than forest's author anyway, but the definition of q is certainly unsanctioned.)

\documentclass[10pt,border=3mm,tikz]{standalone}
% ateb: https://tex.stackexchange.com/a/703039/ addaswyd o ateb MS-SPO: https://tex.stackexchange.com/a/703008/ i gwestiwn apathyy: https://tex.stackexchange.com/q/702992/
\usepackage{forest}
\usetikzlibrary{arrows.meta,shapes.geometric}    % to modify arrow tips, see ch. 16.5 pfgmanual
\makeatletter
\forest@def@processor{q}{}{}{%
  \forest@process@left@toppop\forest@temp
  \forest@process@left@toppop\forest@tempa
  \forest@process@left@toppop\forest@tempb
  \ifnum\forest@temp=0
    \forest@process@right@letprepend\forest@tempb
  \else
    \forest@process@right@letprepend\forest@tempa
  \fi
  \let\forestmathresulttype\forestmathtype@generic
}
\makeatother
\forestset{%
  declare dimen={parental width share}{-1000pt},
  declare boolean={is from diamond}{0},
  declare boolean={is diamond}{0},
  from diamond/.style={%
    is from diamond,
    before typesetting nodes={%
      replace by={%
        [,
          diamond, 
          is diamond,
          inner sep=1.5pt, 
          no edge, 
          anchor=north, 
          draw, 
          append,
          before drawing tree={%
            if={ >Od= {!u.parental width share}{-1000pt}}{
              !u.parental width share/.process={ OOOw3+P w+d d S2 l2 > q {!u.max x}{!u.min x}{!u.n children}{(##1-##2)/(##3-1)} {##1pt} {10pt} },
              for siblings={%
                if={>OO|{is diamond}{is from diamond}}{}{%
                  edge path'/.process={OOOw3+Pw {n}{!u.n children}{!u.parental width share}{(##1-((##2+1)/2))*##3} {(!u.south) ++(##1pt,0pt) -- (.child anchor)}},
                },
              },
            }{},
            y/.option=!u.y,
            y+/.option=!u.min y,
            x/.process={ OOOw3+P {n}{!u.n children}{!u.parental width share}{(##1-((##2+1)/2))*##3}},
          },
        ]%
      },
    },
  },
  branch arrows/.style args={from #1 to #2 with label #3 and from #4 to #5 with label #6}{%
    edge label+/.process={Ow{name}{coordinate [pos=#1] (##1-a) coordinate [pos=#2] (##1-b) coordinate [pos=#4] (##1-c) coordinate [pos=#5] (##1-d)}},
    tikz+/.process={Ow{name}{%
        \draw [{Circle[open]}-Stealth,very thin] (##1-c) ++(0pt,2.5pt) -- ([yshift=2.5pt]##1-d) node [above,my branch arrow label] {#3};
        \draw [{Circle[open]}-Stealth,very thin] (##1-b) ++(0pt,-2.5pt) -- ([yshift=-2.5pt]##1-a) node [below,my branch arrow label] {#6};
      }%
    },
  },
  trunk arrows/.style args={from #1 to #2 with label #3 and from #4 to #5 with label #6}{%
    edge label+/.process={Ow{name}{coordinate [pos=#1] (##1-a) coordinate [pos=#2] (##1-b) coordinate [pos=#4] (##1-c) coordinate [pos=#5] (##1-d)}},
    tikz+/.process={Ow{name}{%
        \draw [{Circle[open]}-Stealth,very thin] (##1-c) ++(2.5pt,0pt) -- ([xshift=2.5pt]##1-d) node [right,my arrow label] {#3};
        \draw [{Circle[open]}-Stealth,very thin] (##1-b) ++(-2.5pt,0pt) -- ([xshift=-2.5pt]##1-a) node [left,my arrow label] {#6};
      }%
    },
  },
  apathyy tree/.style={%
    for tree={%
      draw,
      fit=band,
      s sep'+=20pt,
      delay={content+=\strut},
      font=\sffamily,
    },
    for descendants={anchor=north,
      tier/.option=level,
    },
    anchor=south,
  },
  /tikz/my arrow label/.style={midway,font=\sffamily\tiny,inner sep=1pt,},
  /tikz/my branch arrow label/.style={/tikz/my arrow label,sloped},
}
\begin{document}
\begin{forest}
  apathyy tree,
  [Main()
    [Level Setup, 
      {fill=blue!20}, 
      from diamond,
      branch arrows=from 0.125 to 0.525 with label {text} and from 0.575 to 0.975 with label {other},
      [nested 1
        [nested 1.1]
        [nested 1.2
          [nested 1.2.1
            [nested 1.2.2]
          ]
        ]
      ]
    ]   % just put some color
    [Game,
      calign with current edge,
      trunk arrows=from 0.9 to 0.4 with label {label} and from 0.95 to 0.1 with label {extra},
      [nested 1, from diamond]
      [nested 2, from diamond]
      [nested 3, from diamond]
      [nested 4]
      [nested 5, from diamond]
    ]       % this tree only with ordinary lines
    [Win\_Game(), name=wingame,
      from diamond,
      branch arrows=from 0.125 to 0.525 with label {more} and from 0.575 to 0.975 with label {another},
      [nested 1
        [nested 1.1]
      ]
    ]                   % you need to backslash the underscore
  ]
  \draw [-Stealth] (!r1.west) ..controls +(-25pt,-5pt) and +(-5pt,0pt).. ([yshift=-4pt]!r.center |- !r1.south) ..controls +(5pt,0pt) and +(25pt,-5pt).. (!r3.east);
  \draw [-Stealth] (!r21.west) ..controls +(-25pt,-5pt) and +(-5pt,0pt).. ([yshift=-4pt]!r2.center |- !r21.south) ..controls +(5pt,0pt) and +(25pt,-5pt).. (!r25.east);
  \draw [-Stealth] (wingame.west) ..controls +(-35pt,-10pt) and +(-15pt,0pt).. ([yshift=-5pt]wingame.south) ..controls +(15pt,0pt) and +(35pt,-10pt).. (wingame.east);
\end{forest}
\end{document}

EDIT 2

You can change the styles /tikz/my arrow label and/or /tikz/my branch arrow label using any standard TikZ keys. These aren't Forest styles (and you actually can't use Forest keys in them). So adding something like align=center to those styles will let you use \\ in labels. Or textwidth=<dimension> will make the label wrap lines to the given width. If you want a lot of parallel arrows, you could create specialised styles. Or you can just add them at the end of the Forest environment.

For example, suppose we change the definition of my arrow label (which will also alter my branch arrow label) to

  /tikz/my arrow label/.style={midway,font=\sffamily\tiny,inner sep=1pt,align=center},

and we add

  \draw [{Circle[open]}-Stealth,very thin] (wingame-a) ++(0pt,10pt) -- ([yshift=10pt]wingame-d) node [above,my branch arrow label] {parallel\\multiline};

before \end{forest}. Then we'll get a two-lined label with an additional arrow to the wingame node.

additional arrow with multiline label to wingame

Arrows drawn like this are parallel, but their start and end points won't align because I've not allowed for the angle of the edge. All I've done is shifted the arrow upwards. If you wanted to, you could presumably account for this angle, but hopefully it shouldn't be too critical in most cases because you aren't moving the arrow too far.

14
  • When I try to add extra levels, the middle block (Game) isn't inline with the rest (it's above). I've tried changing the anchor and align settings but the only thing that seems to work is manually using a yshift on the middle block. Sorry for not including this in the first question and or if it should be a standalone.
    – apathyy
    Dec 4, 2023 at 4:07
  • @apathyy Where are you adding levels? I fiddled this so the diamonds didn't align with Game. So it probably needs a different fiddle. Or just to be rethought if you want to repeat it. I was mostly focused on arrows. Maybe we should use an arrow tip for the diamonds as MS-SPO does?
    – cfr
    Dec 4, 2023 at 4:41
  • I was adding nested items within Level Setup, Game and Win_Game
    – apathyy
    Dec 4, 2023 at 11:29
  • @apathyy Like this? (See edited code/image above.)
    – cfr
    Dec 4, 2023 at 16:34
  • Yes! How would you add the diamond to the start of any node connector i.e between Game and Nested 1? And adding the curved arrow say, in win_game(what is r1?)
    – apathyy
    Dec 4, 2023 at 23:39
1

Here's a way to do it:

result

\documentclass[10pt,border=3mm,tikz]{standalone}
\usepackage{forest}
\usetikzlibrary{arrows.meta}    % to modify arrow tips, see ch. 16.5 pfgmanual

\begin{document}
 \begin{forest}
    for tree={draw,edge={Turned Square[open]}-}% all start with a gem
    [Main()
        [Level Setup, {fill=blue!20}]   % just put some color
        [Game, for tree={edge=-}]       % this tree only with ordinary lines
        [Win\_Game()]                   % you need to backslash the underscore
    ]
 \end{forest}
\end{document}

You must log in to answer this question.

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