1

I am trying to implement such a method for spanning a tree over multiple pages in the IEEETran format (double column). I don't want to continue part of the forest on each column on each page (each part of the forest spans over 2 columns on the page). Surrounding \begin{forest} inside \begin{figure*} breaks the forest in the middle of the page and doesn't span multi-page.

MWE:

\documentclass[journal]{IEEEtran}
\usepackage{geometry,blindtext,romannum}
\usepackage[edges]{forest}

\def\hiddenparcommand{\par} \newcommand\otherhiddenparcommand{\par\noindent} \newcommand\hiddencommacommand{, } \forestset{% declare keylist register={split here ids}, split here ids={}, declare keylist register={split here interjects}, the tree parts split here interjects={}, declare keylist={split here auto siblings}{}, declare toks register=split here toks, declare dimen register=tmpdima, tmpdima'=0pt, declare dimen register=tmpdimb, tmpdimb'=0pt, declare dimen register=tmpdimc, tmpdimc'=0pt, to widest/.style={ tikz+={\path (\forestregister{tempdima}, \forestoption{y}) -- (\forestregister{tempdimb}, \forestoption{y});}, }, hide commas/.style={% split here toks+={\hiddencommacommand}, split here toks+={#1}, }, split dir tree pre/.style={% label={[text=gray, anchor=north, font=\scriptsize]below:{[cont.]}{}}, }, split dir tree post/.style={% label={[font=\scriptsize, anchor=south, text=gray]above:{[cont.]}{}}, }, split dir tree auto post/.style={ split dir tree post, tempkeylistc'={}, tmpdimb/.option=y, for nodewalk={ while={ > ORw2+d _+d < On=! & {y}{tmpdimb}{##2-##1} {\textheight-#1} {n'}{1}% }{ next, tempkeylistc/.option=name }% }{}, split here auto siblings/.register=tempkeylistc, tikz+/.process={ OOw2{edge}{id} { \path [##1] (!u.parent anchor |- .north) ++(\forestregister{folder indent},1ex) coordinate (before ##2) |- (.child anchor); \edef\tempa{\foresteoption{split here auto siblings}} \foreach \i in \tempa \path [##1] (before ##2) |- ({forest cs:\i.child anchor}); } }, }, split dir tree/.code={ \forestset{ draw tree stage/.style={ for root'={ tempdima/.min={ >OOw2+d{x}{min x}{####1+####2}% }{tree}, tempdimb/.max={ >OOw2+d{x}{max x}{####1+####2}% }{tree}, for tree={ to widest, }, }, tempcountb'=-1, do until={ strequal((split_here_ids),"") }{ tempkeylistb'={}, tempkeylista'={}, split register={split here ids}{,}{tempcounta,tempkeylistb+}, split register={split here interjects}{,}{temptoksa,tempkeylista+}, split here ids'/.register=tempkeylistb, split here interjects'/.register=tempkeylista, for nodewalk={ draw tree processing order/.style={ filter={tree}{> ORw+n< OR> & {id}{tempcounta}{########1+1}{id}{tempcountb}}% } }{}, for root'={draw tree}, TeX/.process={Rw{temptoksa}{\otherhiddenparcommand ####1\hiddenparcommand}}, tempcountb'/.register=tempcounta, }, for nodewalk={ draw tree processing order/.style={ filter={tree}{>OR>{id}{tempcountb}} } }{}, for root'={draw tree}, }, }% }, split dir here auto/.style n args=2{ split dir tree pre, !next node.split dir tree auto post=#2, split here ids+/.option=id, split={#1}{,}{split here toks,hide commas}, split here interjects/.register=split here toks, }, split dir tree auto/.style={ split dir tree, before drawing tree={ tempdima/.max={y}{tree}, tempdimc/.register=tempdima, tempdimd/.min={y}{tree}, tempdima-/.register=tempdimd, tempdimb'=\textheight, tmpdima'=10ex, tmpdimc'=\pagetotal, while={ >RR>{tempdima}{tempdimb} }{ for nodewalk={ root', until={ > ROw2+d RRw2+d > {tempdimc}{y}{##1-##2} {tmpdima}{tmpdimc}{\textheight-##2-##1} }{next node}, previous node, split dir here auto/.process={R_w2{tmpdima}{continued}{{##2}{##1}}}, next node, tempdima/.option=y, tempdimc/.register=tempdima, tempdima-/.register=tempdimd, tmpdima'=15ex, tmpdimc'=0pt }{}, }, }, }, } \begin{document}

\begin{forest}
    for tree={
        folder,
        grow'=0,
        fit=band,
    },
    split dir tree auto,    
    [ Topics
    [ \Romannum{1}.\, Introduction]
    [ \Romannum{2}.\, Techniques
    [ \Romannum{2}-A.\, Principles of Simulation]
    [ \Romannum{2}-B.\, Classification of Techniques
    [\Romannum{2}-B.1\, Implicit Techniques]
    [\Romannum{2}-B.2\, Partitioning]
    [\Romannum{2}-B.3\, Simulation]
    [\Romannum{2}-B.4\, Algorithms]
    ]
    [\Romannum{2}-C.\, Overview 
    [\Romannum{2}-C.1\, Advantages of Simulation
    [\Romannum{2}-C.1.a\, Computational Burden]
    [\Romannum{2}-C.1.b\, Accuracy]
    [\Romannum{2}-C.1.c\, System Dynamics]
    [\Romannum{2}-C.1.d\, Stability]
    ]
    [\Romannum{2}-C.2\, Challenges
    [\Romannum{2}-C.2.a\, Synchronization]
    [\Romannum{2}-C.2.b\, Subsystems]
    ]
    ]
    ]
    [ \Romannum{3}.\,  Methods
    [\Romannum{3}-A.\, Classification
    [\Romannum{3}-A.1\, Model-one]
    [\Romannum{3}-A.2\, Model-two]
    ]
    [\Romannum{3}-B.\, Comparison
    [\Romannum{3}-B.1\, Time]
    [\Romannum{3}-B.2\, Frequency]
    [\Romannum{3}-B.3\, Mixed]
    ]
    [\Romannum{3}-C.\, Evaluation
    [\Romannum{3}-C.1\, Efficiency]
    [\Romannum{3}-C.2\, Accuracy]
    [\Romannum{3}-C.3\, Ease of Use]
    ]
    ]
    ]
\end{forest}    

\end{document}

enter image description here

enter image description here

  • Welcome! As the answer you linked points out, it's hard to help without code. Can you post a complete minimal example people can compile to reproduce the problem? And can you please clarify what the problem actually is? Do you get an error? Is the output unexpected? Or ...? Note that forest environments really do not lend themselves to being broken across pages. You should first try to avoid the need to do so. If it can't be avoided, you should think about ways to simplify the problem. And you should develop a Plan B. – cfr Dec 03 '23 at 23:21
  • @cfr I have added MWE to the post. Thanks. – LogicLuminary Dec 03 '23 at 23:51

1 Answers1

1

EDIT 3ish

OK. This works in minimal testing. The different parts of the tree are set in figure*. This means they are not necessarily on consecutive pages. Whether this should be considered a bug or a feature is an open question, but that's how this works. I don't know what provision this class has for 'continued' floats. Presumably, these trees will behave in the usual way.

This version also fakes the missing lines and works with trees split into three or more parts. It also works when children are multiple splits distant from their parents.

The code is likely not the most efficient way to do this. My aim was just to get something which works. In comparison with previous versions, this code splits the trees in ways which are not immediately obviously buggy. Doubtless the code is buggy, but I don't currently know what the bugs are. It is thus not subject to quite the same caveats.

Even so,

Caveat emptor


assorted column-spanning trees split over 2 or 3+ pages with faked edges before and after each split

\documentclass[journal]{IEEEtran}
% \documentclass[a4paper,twocolumn]{article}
\usepackage{geometry,kantlipsum,romannum}
\usepackage[edges]{forest}
% ateb: https://tex.stackexchange.com/a/703055 addaswyd o ateb:  ateb: https://tex.stackexchange.com/a/339790/
% a gafodd ei addasu o gôd Sašo Živanović: https://tex.stackexchange.com/a/296771/
\def\hiddenparcommand{\par}
\newcommand\otherhiddenparcommand{\par\noindent}
\newcommand\hiddencommacommand{, }
\newdimen\tempcoordpx
\newdimen\tempcoordtx
\newdimen\tempcoordpy
\newdimen\tempcoordty
\makeatletter
\forestset{%
  declare keylist register={split here ids},
  split here ids={},
  declare keylist register={split here interjects}, 
  split here interjects={},
  declare keylist={split here auto siblings}{},
  declare keylist={split here auto ancestors}{},
  declare toks register=split here toks,
  split here toks={},
  declare count={split dir tree split}{0},
  declare count register={split dir tree splits},
  split dir tree splits'=0,
  declare dimen register=tmpdima,
  tmpdima'=0pt,
  declare dimen register=tmpdimb,
  tmpdimb'=0pt,
  declare dimen register=tmpdimc,
  tmpdimc'=0pt,
  declare dimen register=tmpdimd,
  tmpdimd'=0pt,
  to widest/.style={
    tikz+={\path (\forestregister{tempdima}, \forestoption{y}) -- (\forestregister{tempdimb}, \forestoption{y});},
  },
  hide commas/.style={%
    split here toks+={\hiddencommacommand},
    split here toks+={#1},
  },
  split dir tree pre/.style={%
    label={[text=gray, anchor=north, font=\scriptsize]below:{#1}{}},
  },
  split dir tree pre/.default={[cont.]},
  split dir tree post/.style={%
    label={[font=\scriptsize, anchor=south, text=gray]above:{#1}{}},
  },
  split dir tree post/.default={[cont.]},
  split dir tree auto pre/.style={%
    tempkeylistd'={},
    tmpdimd/.option=y,
    split option={split here auto ancestors}{,}{split dir tree auto pre aux},
    split here auto ancestors'/.register=tempkeylistd,
    tikz+/.process={%
      OOw2{edge}{split dir tree split}
      {
        \path (current top ##2);
        \pgfgetlastxy{\tempcoordtx}{\tempcoordty}
        \edef\tempa{\foresteoption{split here auto ancestors}}
        \foreach \i in \tempa {
          \pgf@relevantforpicturesizefalse
          \path (\i.parent anchor);
          \pgf@relevantforpicturesizetrue
          \pgfgetlastxy{\tempcoordpx}{\tempcoordpy}
          \ifdim\tempcoordty>\tempcoordpy\let\tempcoordty\tempcoordpy\fi
          \def\tempb{[cont.]}
          \path [##1] (\tempcoordpx,\tempcoordty) ++(\forestregister{folder indent},0pt) coordinate (a) -- ([yshift=-1ex]a |- .parent anchor) ;
        }
      }
    },
  },
  split dir tree auto pre aux/.style={%
    for Nodewalk={on invalid=fake}{name=#1,last}{%
      if={>OR<{y}{tmpdimd}}{tempkeylistd+=#1}{}%
    },
  },
  split dir tree auto post/.style={
    split dir tree post,
    tempkeylistc'={},
    tmpdimb/.option=y,
    for nodewalk={
      while={
        > ORw2+d _+d < On=! & {y}{tmpdimb}{##2-##1} {\textheight-#1} {n'}{1}%
      }{
        next,
        tempkeylistc/.option=name
      }%
    }{},
    split here auto siblings/.register=tempkeylistc,
    tikz+/.process={
      OOw2{edge}{id}
      {
        \path [##1] (!u.parent anchor |- .north) ++(\forestregister{folder indent},1ex) coordinate (before ##2) |- (.child anchor);
        \edef\tempa{\foresteoption{split here auto siblings}}
        \foreach \i in \tempa \path [##1] (before ##2) |- ({forest cs:\i.child anchor});
      }
    },
  },
  split dir tree/.code={
    \forestset{
      draw tree stage/.style={
        for root'={
          tempdima/.min={
            >OOw2+d{x}{min x}{####1+####2}%
          }{tree},
          tempdimb/.max={
            >OOw2+d{x}{max x}{####1+####2}%
          }{tree},
          for tree={
            to widest,
          },
        },
        tempcountb'=-1,
        until={
          strequal((split_here_ids),"")
        }{
          tempkeylistb'={},
          tempkeylista'={},
          split register={split here ids}{,}{tempcounta,tempkeylistb+},
          split register={split here interjects}{,}{temptoksa,tempkeylista+},
          split here ids'/.register=tempkeylistb,
          split here interjects'/.register=tempkeylista,
          for nodewalk={
            draw tree processing order/.style={
              filter={tree}{> ORw+n< OR> & {id}{tempcounta}{########1+1}{id}{tempcountb}}%
            }
          }{},
          begin draw/.code={\begin{figure*}\centering\begin{tikzpicture}},
          end draw/.code={\end{tikzpicture}\end{figure*}},
          for root'={draw tree},
          TeX/.process={Rw{temptoksa}{\otherhiddenparcommand ####1\hiddenparcommand}},
          tempcountb'/.register=tempcounta,
        },
        for nodewalk={
          draw tree processing order/.style={
            filter={tree}{>OR>{id}{tempcountb}}
          }
        }{},
        begin draw/.code={\begin{figure*}\centering\begin{tikzpicture}},
        end draw/.code={\end{tikzpicture}\end{figure*}},
        for root'={draw tree},
      },
      for tree={%
        folder,
        grow'=0,
        fit=band,
      },
    }%
  },
  split dir here auto/.style n args=2{
    split dir tree pre,
    tempkeylista={},
    tempcounta'=0,
    tempcountb/.option=split dir tree split,
    for current and ancestors={%
      if={>OR>{n children}{tempcounta}}{%
        for children={%
          if={>OR>{n}{tempcounta}}{%
            tikz+/.process={
              OORw+nw3{edge}{!u.name}{tempcountb}{##1+1}
              {
                \coordinate (a) at ({forest cs:##2.parent anchor} |- current top ##3.north);
                \path [##1] ({forest cs:##2.parent anchor} |- current top ##3.north)  ++(\forestregister{folder indent},1ex)  |- (.child anchor);
              }
            },
          }{},
        },
        tempkeylista+/.option=name,
      }{},
      tempcounta/.option=n,
    },
    split here auto ancestors/.register=tempkeylista,
    split dir tree auto pre,
    !next node.split dir tree auto post=#2,
    split here ids+/.option=id,
    split={#1}{,}{split here toks,hide commas},
    split here interjects/.register=split here toks,
  },
  split dir tree auto/.style={
    split dir tree,
    alias=current top 0,
    before drawing tree={
      tempdima/.max={y}{tree},
      tempdimc/.register=tempdima,
      tempdimd/.min={y}{tree},
      tempdima-/.register=tempdimd,
      tmpdima'=10ex,
      tmpdimc'=\pagetotal,
      while={
        >Rd>{tempdima}{\textheight}
      }{
        for nodewalk={
          root',
          split dir tree split/.register=split dir tree splits,
          until={
            > ROw2+d RRw2+d > {tempdimc}{y}{##1-##2} {tmpdima}{tmpdimc}{\textheight-##2-##1}
          }{next node,split dir tree split/.register=split dir tree splits},
          if nodewalk valid={previous node}{%
            previous node,
            split dir here auto/.process={R_w2{tmpdima}{}{{##2}{##1}}},
            split dir tree splits'+=1,
            next node,
            split dir tree split/.register=split dir tree splits,
            alias=current top \forestoption{split dir tree split},
          }{},
          tempdima/.option=y,
          tempdimc/.register=tempdima,
          tempdima-/.register=tempdimd,
          tmpdima'=15ex,
          tmpdimc'=0pt
        }{},
      },
    },
  },
}
\makeatother
\begin{document}

\begin{forest} split dir tree auto,
[ Topics [ \Romannum{1}., Introduction] [ \Romannum{2}., Techniques [ \Romannum{2}-A., Principles of Simulation] [ \Romannum{2}-B., Classification of Techniques [\Romannum{2}-B.1, Implicit Techniques] [\Romannum{2}-B.2, Partitioning] [\Romannum{2}-B.3, Simulation] [\Romannum{2}-B.4, Algorithms] ] [\Romannum{2}-C., Overview [\Romannum{2}-C.1, Advantages of Simulation [\Romannum{2}-C.1.a, Computational Burden] [\Romannum{2}-C.1.b, Accuracy] [\Romannum{2}-C.1.c, System Dynamics] [\Romannum{2}-C.1.d, Stability] ] [\Romannum{2}-C.2, Challenges [\Romannum{2}-C.2.a, Synchronization] [\Romannum{2}-C.2.b, Subsystems] ] ] ] [ \Romannum{3}., Methods [\Romannum{3}-A., Classification [\Romannum{3}-A.1, Model-one] [\Romannum{3}-A.2, Model-two] ] [\Romannum{3}-B., Comparison [\Romannum{3}-B.1, Time] [\Romannum{3}-B.2, Frequency] [\Romannum{3}-B.3, Mixed] ] [\Romannum{3}-C., Evaluation [\Romannum{3}-C.1, Efficiency] [\Romannum{3}-C.2, Accuracy] [\Romannum{3}-C.3, Ease of Use] ] ] ] \end{forest}

\kant[1-5]

\begin{forest} split dir tree auto,
[ Topics [ \Romannum{1}., Introduction] [ \Romannum{2}., Techniques [ \Romannum{2}-A., Principles of Simulation] [ \Romannum{2}-B., Classification of Techniques [\Romannum{2}-B.1, Implicit Techniques] [\Romannum{2}-B.2, Partitioning] [\Romannum{2}-B.3, Simulation] [\Romannum{2}-B.4, Algorithms] ] [\Romannum{2}-C., Overview [\Romannum{2}-C.1, Advantages of Simulation [\Romannum{2}-C.1.a, Computational Burden] [\Romannum{2}-C.1.b, Accuracy] [\Romannum{2}-C.1.c, System Dynamics] [\Romannum{2}-C.1.d, Stability] ] [\Romannum{2}-C.2, Challenges [\Romannum{2}-C.2.a, Synchronization] [\Romannum{2}-C.2.b, Subsystems] ] ] ] [ \Romannum{3}., Methods [\Romannum{3}-A., Classification [\Romannum{3}-A.1, Model-one] [\Romannum{3}-A.2, Model-two] ] [\Romannum{3}-B., Comparison [\Romannum{3}-B.1, Time] [\Romannum{3}-B.2, Frequency] [\Romannum{3}-B.3, Mixed] ] [\Romannum{3}-C., Evaluation [\Romannum{3}-C.1, Efficiency] [\Romannum{3}-C.2, Accuracy] [\Romannum{3}-C.3, Ease of Use] ] ] ] \end{forest}

\kant[6-10]

\begin{forest} split dir tree auto,
[a[b[c[d[e[f[g[h[i[j[k[l[m[n[o[p[q[r[s[t[u[v[w[x[y[z]]]]]]]]]]]]]]]]]]]]]]]]][b[c[ch[d[dd[e[f[ff[g[ng[h[i[l[ll[m[n[o[p[ph[r[rh[s[t[th[u[w[y]]]]]]]]]]]]]]]]]]]]]]]]]][c[d[e[f[g[h[i[j[k[l[m[n[o[p[q[r[s[t[u[v[w[x[y[z]]]]]]]]]]]]]]]]]]]]]]]]]] \end{forest}

\end{document}

cfr
  • 198,882
  • Good job! Is there a way to keep vertical lines in the page breaks? I have added another image to question to show what I mean. – LogicLuminary Dec 04 '23 at 17:31
  • @user22425400 As I say in the answer you linked, you can't keep the lines because the nodes they are drawn from are gone. You can compensate to some extent by adding lines where there would be edges, but it's tricky to do automatically. – cfr Dec 04 '23 at 17:41
  • I see. Thank you anyway for the provided solution. – LogicLuminary Dec 04 '23 at 18:30
  • @user22425400 If I figure something out, I'll update this. I have got this to work with tableaux proofs, which use forest, but I can't remember if it works automatically and the structure is different. (Also, the solution is basically the work of forest's author.) – cfr Dec 04 '23 at 18:36
  • Appreciate it! If you encounter any updates regarding this automation, your insights would be valuable. – LogicLuminary Dec 04 '23 at 20:39
  • @user22425400 I can restore most of the lines on the first page, but then things go haywire :(. – cfr Dec 05 '23 at 07:05
  • For now, let's leave it as is. I appreciate your time. – LogicLuminary Dec 05 '23 at 17:54
  • @user22425400 See edit if your tree isn't too large and/or children aren't too distant from their parents. But I wouldn't recommend it otherwise. [It is surely possible to do better than this and I'm not seeing it ....] – cfr Dec 06 '23 at 04:03
  • As you mentioned it works for a page break. I've got a big tree that is spanning over 3-4 pages. Only for the first two pages, it works just fine. – LogicLuminary Dec 07 '23 at 04:22
  • @user22425400 Please see above. This code does something neither of the two previous versions did: I don't yet know what this breaks. It fakes the edges and successfully splits a test tree into three parts. – cfr Dec 07 '23 at 19:03