3

I got great help earlier defining a tree using forest (thanks again to cfr!).

I would like to be able to break down a tree into subtrees and draw links between them... either in the same forest or separated forests.

Pictures will be more understable...

FROM :

initial http://www.weboplanet.com/tests/calculerAire2disques.pdf.png

TO something like :

something like that http://www.weboplanet.com/tests/calculerAire2disques.pdf_wish.png

I tried using "phantom" node as root, but subtrees keep on the same line :

something like that http://www.weboplanet.com/tests/calculerAire2disques_wish_resultat.pdf.png

Source code :

\documentclass{standalone}
\usepackage[latin1]{inputenc}
\usepackage{forest}
\usetikzlibrary{shapes.geometric}
\begin{document}
\pgfkeys{/forest,
  decision/.append style={diamond, fill=blue!20, text width=5em, inner sep=.5pt, rounded corners},
  io/.append style={trapezium, trapezium left angle=70,trapezium right angle=-70, minimum height=5mm},
  sequence/.append style={fill=red!20, rounded corners},
  nop/.append style={fill=red!5},
  rotor/.append style={inner sep=3pt,outer sep=0,fill opacity=0.3,minimum width=2cm,circle},
  racine/.append style={minimum width=1cm, fill=white!80,circle,
        tikz={
            \draw [circle,draw,line width=0.5pt] ;
            \draw [->,line width=1pt] () ++(160:4mm) arc (-200:40:4mm);}
        }
    }

\begin{forest}for tree={
  child anchor=north,
  parent anchor=south,
  thick,
  draw,
 align=center,
  font=\sffamily\large,
 }
[,phantom
[{Principal\\\hline \mbox{}\\[-1em]reel r1, r2, aire2, PI\\reel aire1, aire\\} 
    [seq, racine
        [initialisation, name=initSrc,sequence
        ] 
        [Traitement, name=trtSrc,sequence
        ] 
        [Resultat, name=resSrc,sequence
        ]
    ]
]
    [initialisation, name=initDest,sequence
        [{ECRIRE "rayon du disque extérieur ?"}, io]
        [{r1$\leftarrow$ LIRE()}, io]
        [{ECRIRE "rayon du disque interieur ?"}, io]
        [{r2$\leftarrow$ LIRE()}, io]
    ] 
    [Traitement, name=trtDest,sequence
        [{aire1$\leftarrow$ PI*r1*r1} ]
        [{aire2$\leftarrow$ PI*r2*r2} ]
        [{aire$\leftarrow$ r1-r2} ]
    ] 
    [Resultat, name=resDest,sequence
        [{ECRIRE "l'aire vaut ",aire}, io]
    ]
]
\draw[->] (initSrc) to[out=north east,in=south] (initDest);
\draw[->] (trtSrc) to[out=north east,in=south] (trtDest);
\draw[->] (resSrc) to[out=north east,in=south] (resDest);
\end{forest}
\end{document}

Many thanks for your help !

1
  • Please avoid opening and closing lines like "Hi" (already automatically removed) and "Thanks". Salutations, greetings and expressions of gratitude are already implied and only distract from the real question.
    – jub0bs
    Aug 17 '14 at 13:04
2

You might try something like this. This solution uses phantom nodes in combination with fit=rectangle and calign with current to line things up and to ensure that the arrows don't cross nodes and connecting lines. The basic idea is to create the sub-trees as children of the branch on the left but to do so using phantom nodes so that they do not look like sub-trees in the typeset result.

\documentclass{standalone}
\usepackage[utf8]{inputenc}
\usepackage{forest}
\usetikzlibrary{shapes.geometric}
\begin{document}
\pgfkeys{/forest,
  decision/.append style={diamond, fill=blue!20, text width=5em, inner sep=.5pt, rounded corners},
  io/.append style={trapezium, trapezium left angle=70,trapezium right angle=-70, minimum height=5mm},
  sequence/.append style={fill=red!20, rounded corners},
  nop/.append style={fill=red!5},
  rotor/.append style={inner sep=3pt,outer sep=0,fill opacity=0.3,minimum width=2cm,circle},
  racine/.append style={minimum width=1cm, fill=white!80,circle,
        tikz={
            \draw [circle,draw,line width=0.5pt] ;
            \draw [->,line width=1pt] () ++(160:4mm) arc (-200:40:4mm);}
        }
    }

\begin{forest}for tree={
  child anchor=north,
  parent anchor=south,
  thick,
  draw,
  align=center,
  font=\sffamily\large,
 }
[{Principal\\\hline \mbox{}\\[-1em]reel r1, r2, aire2, PI\\reel aire1, aire\\}
    [seq, racine
      [initialisation, name=initSrc,sequence, fit=rectangle
        [,phantom
          [initialisation, name=initDest,sequence
              [{ECRIRE "rayon du disque extérieur ?"}, io]
              [{r1$\leftarrow$ LIRE()}, io]
              [,phantom, calign with current
                [,phantom, calign with current
                  [Traitement, name=trtDest,sequence
                      [{aire1$\leftarrow$ PI*r1*r1} ]
                      [{aire2$\leftarrow$ PI*r2*r2}, calign with current
                        [,phantom, calign with current
                          [Resultat, name=resDest,sequence
                              [{ECRIRE "l'aire vaut ",aire}, io]
                          ]
                        ]
                      ]
                      [{aire$\leftarrow$ r1-r2} ]
                  ]
                ]
              ]
              [{ECRIRE "rayon du disque interieur ?"}, io]
              [{r2$\leftarrow$ LIRE()}, io]
            ]
          ]
        ]
        [Traitement, name=trtSrc,sequence
        ]
        [Resultat, name=resSrc,sequence
        ]
      ]
   ]
]
\draw[->] (initSrc) to[out=south east,in=north] (initDest);
\draw[->] (trtSrc) to[out=south east,in=east] (trtDest);
\draw[->] (resSrc) to[out=south east,in=east] (resDest);
\end{forest}
\end{document}

sub-trees and arrows

5
  • Your code produces the right result ! But my source code is generated from a program (Java written, to define algorithms) and pink nodes could represent modules or subroutines parts that can be broken down in one level or more. It is not so easy to compute the number of phantom level to add...is there a solution that would treat each "module" definition as a separated subtree ? (no matter the alignement ) Aug 17 '14 at 14:10
  • from @cfr proposition, I have just tried "[phantom, l*=N" on each part. It avoids the modification of algorithm structure...but N remains not so easy to compute... Aug 17 '14 at 15:27
  • I'm not really sure I understand your comment. This is just chaining the sub-trees one after another. You could just add the next sub-tree beneath the first/last/*n*th child of the previous sub-tree, sticking a phantom node in between and not worry about the alignment.
    – cfr
    Aug 17 '14 at 22:19
  • 1
    @PatrickDezecache I wonder if you really want a tree at all. Maybe it would be easier to do what you want as a matrix of nodes or using chains or some other facility of tikz? It is just that once you don't want to have things linked as parent-child, using a tree becomes something of a hindrance rather than a help. forest isn't designed to layout disconnected nodes. The whole point is to layout hierarchically connected ones...
    – cfr
    Aug 18 '14 at 0:20
  • you are right, the best would have been 4 forests and links between them (the top first forest, with his 3 components, is the general algorithm and the 3 others are the breakdown of the 3 components) - i tried to use "remember" option to link 2 nodes but I had an error (maybe due by misuse) - // Related to your previous comment, I did not find, in forest documentation, the possibility to set the position of a node beneath another relatively to his name. // Many thanks again, @cfr, for your investment ! Aug 18 '14 at 4:20
0

based on @cfr answer, I will use 'phantom' node plus l option to set node's vertical position :

avantage : easy to change when multilevel nodes

disavantage : links that cross boxes

EDIT : I keep in mind @cfr remark : "...forest isn't designed to layout disconnected nodes...", but it will be easier for me to use the solution below, until I can use links between distinct hierarchical forest.

Code : (only forest block, remaining is unchanged)

...
\begin{forest}
for tree={
  child anchor=north,
  parent anchor=south,
  thick,
  draw,
  align=center,
  font=\sffamily\large
 }
[,phantom
[{Principal\\\hline \mbox{}\\[-1em]reel r1, r2, aire2, PI\\reel aire1, aire\\} 
    [seq, racine
        [Initialisation , name=initSrc,sequence
        ] 
        [Traitement, name=trtSrc,tier=bottom,sequence
        ] 
        [Resultat, name=resSrc,sequence
        ]]]
[,phantom, l*=6  
        [Initialisation, name=initDest,sequence
            [{ECRIRE "rayon du disque extérieur ?"}, io]
            [{r1$\leftarrow$ LIRE()}, io]
            [{ECRIRE "rayon du disque interieur ?"}, io]
            [{r2$\leftarrow$ LIRE()}, io]
        ]]
[,phantom,l*=9 
        [Traitement, name=trtDest,sequence
            [{aire1$\leftarrow$ PI*r1*r1} ]
            [{aire2$\leftarrow$ PI*r2*r2} ]
            [{aire$\leftarrow$ r1-r2} ]
        ]]
[,phantom, l*=12 
        [Resultat, name=resDest,sequence
            [{ECRIRE "l'aire vaut ",aire}, io]
        ]]
]
\draw[->>,dashed] (initSrc) to[out=south,in=west] (initDest);
\draw[->>,dashed] (trtSrc) to[out=south east,in=east] (trtDest);
\draw[->>,dashed] (resSrc) to[out=south,in=east] (resDest);
\end{forest}
....

Image :

solution retenue http://www.weboplanet.com/tests/calculerAire2disques_wish.pdf_final.png

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.