Trying to formalize a long question about (a kind) of validation of my workflow, I realized a good tree would actually summarize well my thoughts.
So... before asking for a proof of concept of this method to generate easily loads of content from one source, I'd like to formalize it visually (this question is a good pretext for me to formalize my thoughts and discover `forest`).
**My question**
How can I grow a second tree starting from courses, going left with a simple structure on 2 levels below courses like
* Courses
- chap01
- sec01_01
- sec01_02
- chap02
- sec02_01
- sec02_02
- sec02_03
- ...
- chap30
- sec30_01
- sec30_02
and having the same system of columns on the left hand side. The option grow'=180 enables me to switch correctly but I need on **both sides** (on the left, for chap and sec, on the right hand side of the tree as it is now) ?
Adapted from https://tex.stackexchange.com/questions/567434/tikz-tree-diagram-classification-with-functional-levels/567923#567923 I have the following (looong) tree... (not so MWE but it'll be the key to my next post)
![TAQuestionTree.png](/image?hash=799a3adc6a6b73841c6ac84614a4f19b2362cab7581b12fe223fefa7e9987da9)
![TAQuestionTree0.png](/image?hash=6fc824a027aa0f87fb07622205412e711c61112f448656bb61d8d49408e4a2f1)
and the other side of the tree
![TAQuestionTree2.png](/image?hash=d890e4a3915dadb8455d8675f36d3850054018c1d42c4ec009c7363213c67ff0)
...that is the direct application of
**How to wrap a frame in a `tcolorbox` when using `\mode<article>`**
https://topanswers.xyz/tex?q=1089
(show frames in beamer ans tcolorboxes in beamerarticle)
**How to wrap `floats` in `tcolorbox` ?**
https://topanswers.xyz/tex?q=1411
(extend the previous to definition, examples, blocs... to tcolorboxes in beamerarticle)
**ignoreframe option (kind of) in Beamerarticle?**
https://topanswers.xyz/tex?q=1093
**Pass pgfkeys arguments to a document to produce multiple outputs**
https://topanswers.xyz/tex?q=1396
(to generate easily multiple outputs based on pgf keys)
**How to use pgfkeys to (elegantly) parameter my document**
https://topanswers.xyz/tex?q=1375
**Flag the lectures you want to compile for a course**
(smart filter of chapters/lectures to produce courses)
https://topanswers.xyz/tex?q=1093
**PS** : I have already fantastic results to produce with a simple `latexmk ` consistent content between different formats that fit the needs of each audience (prof, student, administration, publication, printing, etc all `styles` using the combination of keys).
**PPS** : The same system of choice would be made on the left hand side to describe which chapters/lectures or sections to use to build the content. The formatting is taken care of by the styles on the right hand side.
**PPPS** : I am probably reinventing the wheel here, but the path was nice :)
```
\documentclass{standalone}
\usepackage[edges]{forest}
\forestset{
% This is the style that should be applied in the tree preamble. See the tree
% for what argument it takes.
categorized citations/.style={
delay={
for tree={
% The assumption is that all the nodes without a "tier" option belong
% to the tree on the left. The names of the tiers that citation nodes
% live on will end up to be consecutive numbers.
if tier={}{
% These styles can be adjusted by the user.
common node options,
tree node options,
}{% We assume that anything on a tier is a citation node.
citation format,
% Split the content of the node (separator is ",") and format the
% parts --- if desired.
if citation node autoformat={
split option={content}{,}{format first citation entry, format citation entry},
}{},
% The tier situation is atypical in these trees. There are multiple
% tiers, but there is no hierarchical relation between them --- all
% nodes on tiers are just children of the nodes in the tree. So we
% need to give forest a nudge to get tiers right. This has two parts.
%
% Tiers, part 1. Here we solve the problem of a node in the
% tree with several tier nodes (i.e. citations). The citation nodes
% are siblings, so forest will push them apart in the s (y) dimension
% --- this is so because tier alignment happens later. But if we
% make the l (x) coordinates of the nodes different enough, the nodes
% will not "bump" and will happily end up with the same s (y) coordinate.
% We try to make them minimally different (and thus small), so that
% we don't accidentally push them too much to the right.
l=\forestregister{citation boxes offset}+(tier()-1)*(\forestregister{citation node text width}+2*\pgfkeysvalueof{/pgf/inner xsep}+2*\pgfkeysvalueof{/pgf/outer xsep}+0.1pt),
},
},
% Tiers, part 2.
% Here we tell forest about the relative order of tiers (and thus boxes
% on the right). We need to do this because when we write down the tree,
% we just put the citation nodes next to each other (as siblings). The
% idea here is to create a dummy node on each tier, with structure
% [1[2[3...]]], and remove them all once they do their job. This "tier
% header" is created automatically from the argument to "folders with
% citation blocks" style.
temptoksa={}, % This will hold the argument to "prepend".
% This will hold a call of "draw tier box" for each tier box (in reverse
% order):
draw tier boxes/.style={},
tempcounta'=0, % The current tier number.
temptoksb={}, % The closing brackets to append to temptoksa.
split={#1}{,}{add first citation tier, add citation tier},
% Insert the closing brackets.
temptoksa+/.register=temptoksb,
% The tier header specification is constructed, let's put it in the tree!
prepend/.register=temptoksa,
},
% After all nodes are positioned, we define style "draw tier box" which
% draws a citation box and its contents.
before drawing tree={% #1 = tier name
% Remember the topmost and the bottommost position in the entire tree
% (folders and citations):
tempdimya/.max={y()+max_y()}{tree},
tempdimyb/.min={y()+min_y()}{tree},
% The first argument of this style is a tier name; in the code, it is
% referred to by ####1, due to being embedded in .process
draw tier box/.style/.process=R2w2{tempdimya}{tempdimyb}{
% ##1, ##2 = tempdimya, tempdimyb
% Get the leftmost and the right position in the citation box (i.e the
% given tier):
tempdimxa/.max={x()+max_x()}{filter={tree}{strequal(tier(),"####1")}},
tempdimxb/.min={x()+min_x()}{filter={tree}{strequal(tier(),"####1")}},
% "draw tier box" style is called from the "draw tree method", so we
% just draw the citation box directly.
TeX/.process=R2ORw4
{tempdimxa}{tempdimxb}{####1.content}{citation box label position}{
% ########1, ########2 = tempdimxa, tempdimxb
% ########3 = the content of the dummy tier node
% ########4 = "citation box label position" register
\node[
fit={(########1,##1) (########2,##2)},
citation box options,
% The box is labeled by the content of the dummy tier header node.
label={[citation box label options]########4:########3}]{};
},
% Draw the citation nodes of this box (i.e. on this tier), and their edges.
for filter={tree}{strequal(tier(),"####1")}{draw tree node, draw tree edge},
},
},
% We need to draw stuff in a very particular order, so that the edges from
% citation nodes on tier 2 go behind citation box 1, etc.
draw tree method/.style={
% Draw the tree on the left (nodes and edges).
for filter={tree}{strequal(tier(),"")}{draw tree node, draw tree edge},
% Draw the citation boxes (and their contents) --- in reverse order!
draw tier boxes,
% Finally, draw any decorations.
for tree=draw tree tikz,
},
},
% How should the nodes in the blocks on the right look like?
citation format/.style={
% Don't change "text width" directly. We need to remember it for later (see
% Tiers, part 1), so use "citation node text width" register.
text width/.register=citation node text width,
% Adjust these styles for other options.
common node options,
citation node options,
},
% We use these two styles when splitting the citation box specification (the
% argument of "categorized citations").
add first citation tier/.style={
add citation tier={#1},
% Get rid of the dummy citation nodes after they have done their job.
temptoksa+={, before computing xy=remove},
},
add citation tier/.style={
tempcounta'+=1, % Increase the tier number.
% Add the dummy citation specification. We put it on tier 1/2/3..., give it
% the same name (just in case we want to format them independently), and
% apply the standard citation node format.
temptoksa+/.process=Rw{tempcounta}{[#1, tier=##1, name=##1, citation format%]
},
% Well need an extra closing bracket at the end:
temptoksb+=%[
],
% Prepend the command to draw this particular citation box to "draw tier
% boxes". We *pre*pend because it is crucial that citation boxes are drawn
% in reverse order: the idea is that a citation box gets drawn on top of
% any edges coming from citation boxes further away from the tree; in
% effect, the edges to citations will go below intermediate citation boxes.
draw tier boxes/.prefix style/.process=Rw{tempcounta}{draw tier box=##1},
},
% An update to the "folder" style from the "edges" library. It (or something
% like it) will be included in the next release of forest.
folder v2/.style={
calign=child,
calign primary child=1,
% This is necessary for "tempdims" calculation below to work properly.
anchor=parent,
after packing node={
if n children=0{}{
tempdiml=l_sep()-l("!1"), % l-shift
tempdims={abs(max_s("",""))+abs(min_s("!1",""))+s_sep()}, % s-shift
for children={
l+=tempdiml,
s+=tempdims()*(0.5-reversed())*2,
edge={rotate/.option=!parent.grow},
% We don't use the values of "parent anchor" and "child anchor" here
% (we use ".-children last" and ".parent" directly), because the user
% might want to use those otherwise if the folder is embedded in a
% larger tree.
edge path'/.expanded={
([xshift=\forestregister{folder indent}]!u.-children last) |- (.parent)
},
},
fit=band, % to avoid overlapping nodes with their (greatgreat...)uncles.
},
},
},
% In "folder with cites", we separate category and citation nodes, and pack
% them separately. So this style really does all the work in "before/after
% packing node": separate category and citation nodes just before packing, and
% put them back together after packing.
%
% This is just a temporary node we'll need to store a copy of the parent
% folder node into. We need it because somebody didn't implement "create" to
% accept a relative node name and thus act as a copying operation. To be done.-
create'={[,name=folder@temp]},
folder with cites/.style={
before packing node={
% Make a copy of the parent folder node (without the subtree).
for name/.process=_Ow{folder@temp}{id}{
append''={!{id=##1}},
},
% Here I don't follow my own advice (from the forest manual) and call the
% experimental "do dynamics" from within "process keylist(')" (well, not
% explicitly, effectively so, because "before/after packing node" are
% internally called as if by "process keylist'"). The bad news is that
% "do dynamics" in fact does not work as expected here ...
do dynamics,
% ... but the good news is that I now know at least one thing that is
% wrong with it: it fails to set "last dynamic node". This will be
% investigated ... until then, a workaround:
for group={name=folder@temp,last}{alias=folder@temp@parent},
% In fact, there was another problem with "do dynamics". It did not
% update all the node options containing the hierarchical information
% about the tree. So this key now grew (the new definition below; to be
% included in the next release of forest) an argument: a relative node
% name instructing it which nodes to update after doing the dynamic
% thing. (Note that we can safely use "do dynamics" twice; no dynamic
% operations are performed the second time, as the dynamic queue is
% empty, but the info will get updated.)
do dynamics=folder@temp@parent,
% Move all citation nodes (i.e. a nodes with non-empty tier option) into
% the copy of the parent.
for children={
if tier={}{}{
for name/.process=_Ow{folder@temp@parent}{id}{
append={!{id=##1}},
},
},
},
% Do the dynamic operations immediately --- ahh yes, we must do this
% because we're in the middle of packing a node!
do dynamics, do dynamics=folder@temp@parent,
},
% Apply the (updated) folder style to whatever children remained in the
% original parent.
folder v2,
after packing node={
alias=folder@temp@current,
for name={folder@temp@parent}{
for children={
% We do this because gdjgfjdfgsdj ... remove the line and see what
% happens to the tall adjacent citations on tier 2 (children of
% "Crank and slider" and "Bell crank").
l+={abs(max_l("",""))+abs(min_l("!u",""))+l_sep("!u")},
},
% calign/.register=citation nodes calign,
% How should we calign the citation nodes after packing them?
citation nodes calign,
% Pack the citation nodes within the copy of the parent ...
pack',
% ... and then put them back into the original parent. It does not
% really matter where to put them, so we just append.
for children={
for name/.process=_Ow{folder@temp@current}{id}{
append={!{id=##1}},
},
},
},
% For the final time ...
do dynamics,
},
},
declare dimen register=citation node text width,
declare dimen register=citation boxes offset,
declare boolean register=citation node autoformat,
declare toks register=citation box label position,
}
\makeatletter
\forestset{
% Let's patch up "do dynamics" --- to be included in the next release of forest.
do dynamics/.code={%
\the\forest@do@dynamics
\forest@do@dynamics{}%
\forest@forthis{%
\forest@nameandgo{#1}%
\forest@node@Compute@numeric@ts@info{\forest@cn}%
}%
},
do dynamics/.default=!{root'},
}
\makeatother
% These are the formatting options and should be (reasonably) safe to adjust.
\forestset{
common node options/.style={
% "grow" will only work for 0 and 180. For other directions, the "draw tier
% box" style would need to be generalized.
grow'=0,
},
% This style is applied to all the category nodes, i.e. the nodes on the
% left.
tree node options/.style={
% Some basic stuff ...
draw, /tikz/align=center,
% For single citation nodes connected to a tree nodes, it even works
% without this (assuming that the default parent anchor is center). But for
% the fancy "forked edge" calignment of citation nodes, this is necessary.
parent anchor=children,
% The shift of the parent anchor for the folder node (a register applying
% to all folder nodes):
folder indent=1em,
% Nodes on levels 0, 1 and 2 are drawn with "forked edge"s.
% Nodes on levels 2, 3, ... are folders. There is no limit on the
% number of levels.
%
% Feel free to change the level where the transition from forked edge to
% folders occurs, or even to mix them. Note that key "forked edge" sets the
% type of the edge towards the parent node; it must be set for each child. Key
% "folder" (either the original, v2, or "folder with cites"), on the other hand,
% influences the positions and edges of its children; it must be only used on
% the parent node.
%
% We also set text widths, opacities etc. for each level here. The
% color is set in the tree itself.
if level=0{
fill opacity=0.45, text width=3.5cm, rounded corners=3pt,
}{if level=1{
fill opacity=0.45, text width=2.5cm, rounded corners=3pt,
forked edge,
}{
if level=2{
fill opacity=0.30, text width=2.0cm, rounded corners=3pt,
forked edge,
% The "l sep" (here and below) influences both the folder--file
% distance and the distance to citation nodes.
folder with cites, l sep+=1em,
}{
if level=3{
fill opacity=0.30, text width=1.5cm, rounded corners=2pt,
folder with cites, l sep+=1em,
}{% level >= 4
fill opacity=0.15, text width=1.5cm, rounded corners=2pt,
folder with cites, l sep+=1em,
},
},
},
},
},
% The width of the citation nodes.
citation node text width=1.5cm,
% Other options applying to citation nodes (don't change "text width" here!):
citation node options/.style={
draw, /tikz/align=center, rounded corners=2pt,
fill=brown, fill opacity=0.6,
% This sets the separation between the citation boxes:
l sep=2em,
% The "anchor" key specifies center vertical alignment to the parent. The
% "child anchor" says that's where the edge will start too. We
% most probably want to keep these as they are.
anchor=parent, child anchor=parent,
},
% How shall we align citations in the unlikely case that we have more than
% one citation node belonging to a category node on a single tier (see the blue
% "citation" in the example tree)? Let's have a very fancy setup, center
% caligned with forked edges, by default.
citation nodes calign/.style={
calign=center, forked edges, for children={fork sep=2em},
},
% We can push the citation boxes a bit further away from the tree. By
% default, the "l sep" of the parents of citations nodes is in effect.
citation boxes offset=0em,
% How should a citation box look like? Note that we want "fill opacity=1"
% (the default) here, because we want the citation box to partially hide the
% edges from citations to the folders.
/tikz/citation box options/.style={
fill=blue!20, draw=red, thick,
},
% Format the citation box labels:
/tikz/citation box label options/.style={
},
% Where should the citation box labels appear?
citation box label position=north,
% These two keys are used to automatically format the list of references in a
% citation node.
format first citation entry/.style={content'=\mbox{[#1]}},
format citation entry/.style={content+'=\discretionary{}{}{}\mbox{[#1]}},
% A register saying whether we want to autoformat citations:
citation node autoformat=true,
}
\begin{document}
\begin{forest}
% Style "categorized citations" takes an argument specifying the
% (comma-separated) labels of citation boxes. Each citation block will reside
% on its own tier, the tiers numbered 1,2,3... So to put a citation into
% block A/B/C, write "tier=1/2/3" into the citation node. The number of
% labels given here must match the number of tiers used below, i.e. an empty
% citation box will lead to an error. If you list too few labels here, the
% extra tiers will be ignored (without producing an error).
categorized citations={standard,prof,student}
[Courses, fill=gray
[common, for tree={fill=blue}
[class
[book]
[beamer]
[article]
[exam]
[...]
]
[Author related
[author]
[title]
[subtitle]
]
[cover-image
[cover Course1]
[cover Course2]
[cover Course3]
[cover Course4]
[...]
[error-handler]
[tikzexternalize
[yes
[,tier=1]
[,tier=2]
]
[no
[,tier=3]
]
]
]
[University
[institute]
[department]
[logo
[standard]
[Transparent]
[BW]
]
]
]
[notes, for tree={fill=brown}
[page-format
[standard
[,tier=1]
]
[wide
[,tier=2]
]
[tufte like
[,tier=3]
]
]
[header-format
[simple
[,tier=1]
]
[fancy
[,tier=2]
[,tier=3]
]
]
[fonts
[Garamond
[,tier=1]
]
[Euler]
[Times]
[Avant
[,tier=2]
[,tier=3]
]
]
[caption]
[float-counters]
[frames in tcb
[yes
[,tier=1]
[,tier=2]
]
[no
[,tier=3]
]
]
[env in tcb
[example
[,tier=1]
[,tier=2]
]
[definition
[,tier=1]
[,tier=2]
]
[block
[,tier=1]
[,tier=2]
]
[alertblock
[,tier=1]
[,tier=2]
]
]
[multipage
[2 on 1
[,tier=2]
]
[4 on 1]
[block]
]
[tocdepth
[4,tier=1]
[4,tier=2]
[2,tier=3]
]
[section depth
[4,tier=1]
[4,tier=2]
[3,tier=3]
]
[extract
[yes
[,tier=1]
[,tier=2]
]
[no
[,tier=3]
]
]
]
[beamer,
% An easy way to set the color of the entire subtree. The opacity is set,
% per-level, in "tree node options".
for tree={fill=red},
[theme
[Simple
[,tier=1]
]
[Cambridge
[,tier=2]
]
[Hannover
[,tier=3]
]
]
[colortheme
[no color
[,tier=1]
]
[beetle
[,tier=2]
]
[crane
[,tier=3]
]
]
[font
[,tier=1]
[,tier=2]
[professionalfonts,tier=3]
[page-format
[normal
[,tier=1]
]
[show only notes
[,tier=2]
]
[show notes on second screen=right
[,tier=3]
]
]
]
[university colors
]
[tocdepth
[2,tier=1]
[2,tier=2]
[2,tier=3]
]
]
%
]
\end{forest}
\end{document}
```
as for my poor attempt to describe left tree
```
\documentclass{standalone}
\usepackage[edges]{forest}
\forestset{
% This is the style that should be applied in the tree preamble. See the tree
% for what argument it takes.
categorized citations/.style={
delay={
for tree={
% The assumption is that all the nodes without a "tier" option belong
% to the tree on the left. The names of the tiers that citation nodes
% live on will end up to be consecutive numbers.
if tier={}{
% These styles can be adjusted by the user.
common node options,
tree node options,
}{% We assume that anything on a tier is a citation node.
citation format,
% Split the content of the node (separator is ",") and format the
% parts --- if desired.
if citation node autoformat={
split option={content}{,}{format first citation entry, format citation entry},
}{},
% The tier situation is atypical in these trees. There are multiple
% tiers, but there is no hierarchical relation between them --- all
% nodes on tiers are just children of the nodes in the tree. So we
% need to give forest a nudge to get tiers right. This has two parts.
%
% Tiers, part 1. Here we solve the problem of a node in the
% tree with several tier nodes (i.e. citations). The citation nodes
% are siblings, so forest will push them apart in the s (y) dimension
% --- this is so because tier alignment happens later. But if we
% make the l (x) coordinates of the nodes different enough, the nodes
% will not "bump" and will happily end up with the same s (y) coordinate.
% We try to make them minimally different (and thus small), so that
% we don't accidentally push them too much to the right.
l=\forestregister{citation boxes offset}+(tier()-1)*(\forestregister{citation node text width}+2*\pgfkeysvalueof{/pgf/inner xsep}+2*\pgfkeysvalueof{/pgf/outer xsep}+0.1pt),
},
},
% Tiers, part 2.
% Here we tell forest about the relative order of tiers (and thus boxes
% on the right). We need to do this because when we write down the tree,
% we just put the citation nodes next to each other (as siblings). The
% idea here is to create a dummy node on each tier, with structure
% [1[2[3...]]], and remove them all once they do their job. This "tier
% header" is created automatically from the argument to "folders with
% citation blocks" style.
temptoksa={}, % This will hold the argument to "prepend".
% This will hold a call of "draw tier box" for each tier box (in reverse
% order):
draw tier boxes/.style={},
tempcounta'=0, % The current tier number.
temptoksb={}, % The closing brackets to append to temptoksa.
split={#1}{,}{add first citation tier, add citation tier},
% Insert the closing brackets.
temptoksa+/.register=temptoksb,
% The tier header specification is constructed, let's put it in the tree!
prepend/.register=temptoksa,
},
% After all nodes are positioned, we define style "draw tier box" which
% draws a citation box and its contents.
before drawing tree={% #1 = tier name
% Remember the topmost and the bottommost position in the entire tree
% (folders and citations):
tempdimya/.max={y()+max_y()}{tree},
tempdimyb/.min={y()+min_y()}{tree},
% The first argument of this style is a tier name; in the code, it is
% referred to by ####1, due to being embedded in .process
draw tier box/.style/.process=R2w2{tempdimya}{tempdimyb}{
% ##1, ##2 = tempdimya, tempdimyb
% Get the leftmost and the right position in the citation box (i.e the
% given tier):
tempdimxa/.max={x()+max_x()}{filter={tree}{strequal(tier(),"####1")}},
tempdimxb/.min={x()+min_x()}{filter={tree}{strequal(tier(),"####1")}},
% "draw tier box" style is called from the "draw tree method", so we
% just draw the citation box directly.
TeX/.process=R2ORw4
{tempdimxa}{tempdimxb}{####1.content}{citation box label position}{
% ########1, ########2 = tempdimxa, tempdimxb
% ########3 = the content of the dummy tier node
% ########4 = "citation box label position" register
\node[
fit={(########1,##1) (########2,##2)},
citation box options,
% The box is labeled by the content of the dummy tier header node.
label={[citation box label options]########4:########3}]{};
},
% Draw the citation nodes of this box (i.e. on this tier), and their edges.
for filter={tree}{strequal(tier(),"####1")}{draw tree node, draw tree edge},
},
},
% We need to draw stuff in a very particular order, so that the edges from
% citation nodes on tier 2 go behind citation box 1, etc.
draw tree method/.style={
% Draw the tree on the left (nodes and edges).
for filter={tree}{strequal(tier(),"")}{draw tree node, draw tree edge},
% Draw the citation boxes (and their contents) --- in reverse order!
draw tier boxes,
% Finally, draw any decorations.
for tree=draw tree tikz,
},
},
% How should the nodes in the blocks on the right look like?
citation format/.style={
% Don't change "text width" directly. We need to remember it for later (see
% Tiers, part 1), so use "citation node text width" register.
text width/.register=citation node text width,
% Adjust these styles for other options.
common node options,
citation node options,
},
% We use these two styles when splitting the citation box specification (the
% argument of "categorized citations").
add first citation tier/.style={
add citation tier={#1},
% Get rid of the dummy citation nodes after they have done their job.
temptoksa+={, before computing xy=remove},
},
add citation tier/.style={
tempcounta'+=1, % Increase the tier number.
% Add the dummy citation specification. We put it on tier 1/2/3..., give it
% the same name (just in case we want to format them independently), and
% apply the standard citation node format.
temptoksa+/.process=Rw{tempcounta}{[#1, tier=##1, name=##1, citation format%]
},
% Well need an extra closing bracket at the end:
temptoksb+=%[
],
% Prepend the command to draw this particular citation box to "draw tier
% boxes". We *pre*pend because it is crucial that citation boxes are drawn
% in reverse order: the idea is that a citation box gets drawn on top of
% any edges coming from citation boxes further away from the tree; in
% effect, the edges to citations will go below intermediate citation boxes.
draw tier boxes/.prefix style/.process=Rw{tempcounta}{draw tier box=##1},
},
% An update to the "folder" style from the "edges" library. It (or something
% like it) will be included in the next release of forest.
folder v2/.style={
calign=child,
calign primary child=1,
% This is necessary for "tempdims" calculation below to work properly.
anchor=parent,
after packing node={
if n children=0{}{
tempdiml=l_sep()-l("!1"), % l-shift
tempdims={abs(max_s("",""))+abs(min_s("!1",""))+s_sep()}, % s-shift
for children={
l+=tempdiml,
s+=tempdims()*(0.5-reversed())*2,
edge={rotate/.option=!parent.grow},
% We don't use the values of "parent anchor" and "child anchor" here
% (we use ".-children last" and ".parent" directly), because the user
% might want to use those otherwise if the folder is embedded in a
% larger tree.
edge path'/.expanded={
([xshift=\forestregister{folder indent}]!u.-children last) |- (.parent)
},
},
fit=band, % to avoid overlapping nodes with their (greatgreat...)uncles.
},
},
},
% In "folder with cites", we separate category and citation nodes, and pack
% them separately. So this style really does all the work in "before/after
% packing node": separate category and citation nodes just before packing, and
% put them back together after packing.
%
% This is just a temporary node we'll need to store a copy of the parent
% folder node into. We need it because somebody didn't implement "create" to
% accept a relative node name and thus act as a copying operation. To be done.-
create'={[,name=folder@temp]},
folder with cites/.style={
before packing node={
% Make a copy of the parent folder node (without the subtree).
for name/.process=_Ow{folder@temp}{id}{
append''={!{id=##1}},
},
% Here I don't follow my own advice (from the forest manual) and call the
% experimental "do dynamics" from within "process keylist(')" (well, not
% explicitly, effectively so, because "before/after packing node" are
% internally called as if by "process keylist'"). The bad news is that
% "do dynamics" in fact does not work as expected here ...
do dynamics,
% ... but the good news is that I now know at least one thing that is
% wrong with it: it fails to set "last dynamic node". This will be
% investigated ... until then, a workaround:
for group={name=folder@temp,last}{alias=folder@temp@parent},
% In fact, there was another problem with "do dynamics". It did not
% update all the node options containing the hierarchical information
% about the tree. So this key now grew (the new definition below; to be
% included in the next release of forest) an argument: a relative node
% name instructing it which nodes to update after doing the dynamic
% thing. (Note that we can safely use "do dynamics" twice; no dynamic
% operations are performed the second time, as the dynamic queue is
% empty, but the info will get updated.)
do dynamics=folder@temp@parent,
% Move all citation nodes (i.e. a nodes with non-empty tier option) into
% the copy of the parent.
for children={
if tier={}{}{
for name/.process=_Ow{folder@temp@parent}{id}{
append={!{id=##1}},
},
},
},
% Do the dynamic operations immediately --- ahh yes, we must do this
% because we're in the middle of packing a node!
do dynamics, do dynamics=folder@temp@parent,
},
% Apply the (updated) folder style to whatever children remained in the
% original parent.
folder v2,
after packing node={
alias=folder@temp@current,
for name={folder@temp@parent}{
for children={
% We do this because gdjgfjdfgsdj ... remove the line and see what
% happens to the tall adjacent citations on tier 2 (children of
% "Crank and slider" and "Bell crank").
l+={abs(max_l("",""))+abs(min_l("!u",""))+l_sep("!u")},
},
% calign/.register=citation nodes calign,
% How should we calign the citation nodes after packing them?
citation nodes calign,
% Pack the citation nodes within the copy of the parent ...
pack',
% ... and then put them back into the original parent. It does not
% really matter where to put them, so we just append.
for children={
for name/.process=_Ow{folder@temp@current}{id}{
append={!{id=##1}},
},
},
},
% For the final time ...
do dynamics,
},
},
declare dimen register=citation node text width,
declare dimen register=citation boxes offset,
declare boolean register=citation node autoformat,
declare toks register=citation box label position,
}
\makeatletter
\forestset{
% Let's patch up "do dynamics" --- to be included in the next release of forest.
do dynamics/.code={%
\the\forest@do@dynamics
\forest@do@dynamics{}%
\forest@forthis{%
\forest@nameandgo{#1}%
\forest@node@Compute@numeric@ts@info{\forest@cn}%
}%
},
do dynamics/.default=!{root'},
}
\makeatother
% These are the formatting options and should be (reasonably) safe to adjust.
\forestset{
common node options/.style={
% "grow" will only work for 0 and 180. For other directions, the "draw tier
% box" style would need to be generalized.
grow'=180,
},
% This style is applied to all the category nodes, i.e. the nodes on the
% left.
tree node options/.style={
% Some basic stuff ...
draw, /tikz/align=center,
% For single citation nodes connected to a tree nodes, it even works
% without this (assuming that the default parent anchor is center). But for
% the fancy "forked edge" calignment of citation nodes, this is necessary.
parent anchor=children,
% The shift of the parent anchor for the folder node (a register applying
% to all folder nodes):
folder indent=1em,
% Nodes on levels 0, 1 and 2 are drawn with "forked edge"s.
% Nodes on levels 2, 3, ... are folders. There is no limit on the
% number of levels.
%
% Feel free to change the level where the transition from forked edge to
% folders occurs, or even to mix them. Note that key "forked edge" sets the
% type of the edge towards the parent node; it must be set for each child. Key
% "folder" (either the original, v2, or "folder with cites"), on the other hand,
% influences the positions and edges of its children; it must be only used on
% the parent node.
%
% We also set text widths, opacities etc. for each level here. The
% color is set in the tree itself.
if level=0{
fill opacity=0.45, text width=3.5cm, rounded corners=3pt,
}{if level=1{
fill opacity=0.45, text width=2.5cm, rounded corners=3pt,
forked edge,
}{
if level=2{
fill opacity=0.30, text width=2.0cm, rounded corners=3pt,
forked edge,
% The "l sep" (here and below) influences both the folder--file
% distance and the distance to citation nodes.
folder with cites, l sep+=1em,
}{
if level=3{
fill opacity=0.30, text width=1.5cm, rounded corners=2pt,
folder with cites, l sep+=1em,
}{% level >= 4
fill opacity=0.15, text width=1.5cm, rounded corners=2pt,
folder with cites, l sep+=1em,
},
},
},
},
},
% The width of the citation nodes.
citation node text width=1.5cm,
% Other options applying to citation nodes (don't change "text width" here!):
citation node options/.style={
draw, /tikz/align=center, rounded corners=2pt,
fill=brown, fill opacity=0.6,
% This sets the separation between the citation boxes:
l sep=2em,
% The "anchor" key specifies center vertical alignment to the parent. The
% "child anchor" says that's where the edge will start too. We
% most probably want to keep these as they are.
anchor=parent, child anchor=parent,
},
% How shall we align citations in the unlikely case that we have more than
% one citation node belonging to a category node on a single tier (see the blue
% "citation" in the example tree)? Let's have a very fancy setup, center
% caligned with forked edges, by default.
citation nodes calign/.style={
calign=center, forked edges, for children={fork sep=2em},
},
% We can push the citation boxes a bit further away from the tree. By
% default, the "l sep" of the parents of citations nodes is in effect.
citation boxes offset=0em,
% How should a citation box look like? Note that we want "fill opacity=1"
% (the default) here, because we want the citation box to partially hide the
% edges from citations to the folders.
/tikz/citation box options/.style={
fill=blue!20, draw=red, thick,
},
% Format the citation box labels:
/tikz/citation box label options/.style={
},
% Where should the citation box labels appear?
citation box label position=north,
% These two keys are used to automatically format the list of references in a
% citation node.
format first citation entry/.style={content'=\mbox{[#1]}},
format citation entry/.style={content+'=\discretionary{}{}{}\mbox{[#1]}},
% A register saying whether we want to autoformat citations:
citation node autoformat=true,
}
\begin{document}
\begin{forest}
% Style "categorized citations" takes an argument specifying the
% (comma-separated) labels of citation boxes. Each citation block will reside
% on its own tier, the tiers numbered 1,2,3... So to put a citation into
% block A/B/C, write "tier=1/2/3" into the citation node. The number of
% labels given here must match the number of tiers used below, i.e. an empty
% citation box will lead to an error. If you list too few labels here, the
% extra tiers will be ignored (without producing an error).
categorized citations={chapters/lectures,sections,}
[Courses, fill=gray
[chap01, for tree={fill=blue}
[sec01-01]
[sec01-02]
[...]
[sec01-n]
]
[chap02, for tree={fill=blue}
[sec02-01]
[sec02-02]
[...]
[sec02-n]
]
[chap03, for tree={fill=blue}
[sec03-01]
[sec03-02]
[...]
[sec03-n]
]
[...]
[chap30,for tree={fill=red},
[sec30-01
[,tier=1]
[sec30-02
[,tier=2]
]
[sec03-03
[,tier=2]
]
]
]
]
\end{forest}
\end{document}
```