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