summaryrefslogtreecommitdiff
path: root/graphics/pgf/contrib/forest/forest-libs.dtx
blob: 9873abfa54ad3a6d099d0c856c7f6cdf0fa7acbc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
% \CheckSum{236}
% \iffalse meta-comment
% forest-libs.dtx
%% `forest-libs' is a collection of libraries for package `forest'.
%%
%% Copyright (c) 2012-2017 Saso Zivanovic
%%                    (Sa\v{s}o \v{Z}ivanovi\'{c})
%% saso.zivanovic@guest.arnes.si
%%
%% This work may be distributed and/or modified under the
%% conditions of the LaTeX Project Public License, either version 1.3
%% of this license or (at your option) any later version.
%% The latest version of this license is in
%% 
%%   http://www.latex-project.org/lppl.txt
%%   
%% and version 1.3 or later is part of all distributions of LaTeX
%% version 2005/12/01 or later.
%%
%% This work has the LPPL maintenance status `author-maintained'.
%% 
%% This file is a part of package `forest'. For the list of files
%% constituting the package see main source file of the package,
%% `forest.dtx', or the derived `forest.sty'.
%%
% \fi
%
% \section{Libraries}
%
% This chapter contains not only the reference of commands found in libraries and some examples of
% their usage, but also their definitions. This is done in the hope that these definitions, being
% mostly styles, will be useful as examples of the core features of the package.  I even managed to
% comment them a bit \dots
%
% \paragraph{Disclaimer.}  At least in the initial stages of a library's development, the function
% and interface of macros and keys defined in a library might change without backwards compatibility
% support!  Though I'll try to keep this from happening \dots
%
%    \begin{macrocode}
\RequirePackage{forest}
%    \end{macrocode}
%
%\iffalse
%<*linguistics>
%\fi
% \librarysection{linguistics}
%    \begin{macrocode}
\ProvidesForestLibrary{linguistics}[2017/07/14 v0.1.2]
%    \end{macrocode}
%
% Defaults:
%    \begin{macrocode}
\forestset{
  linguistics@set@baseline/.style={
    if phantom={for next node=linguistics@set@baseline}{baseline}
  },
  libraries/linguistics/defaults/.style={
    default preamble={
%    \end{macrocode}
% Edges of the children will ``meet'' under the node:
%    \begin{macrocode}
     sn edges,
%    \end{macrocode}
% The root of the tree will be aligned with the text \dots\ or, more commonly, the example number.
% More precisely, we actually align the first (in linear order) non-phantom node.  This covers the
% common case of side-by-side trees joined with a phantom root.
%    \begin{macrocode}
    before drawing tree={
      if nodewalk valid={name=forest@baseline@node}{}{linguistics@set@baseline},
    },
%    \end{macrocode}
% Enable (centered) multi-line nodes.
%    \begin{macrocode}
     for tree={align=center},
    },
  },
}
%    \end{macrocode}
%    
% There's no linguistics without c-command\footnote{The definition of c-command is as follows: a node c-commands its siblings and their descendants.} \dots
% \begin{syntax}
% \indexitem{step>c-commanded} Visit all the nodes c-commanded by the current node.
% \indexitem{step>c-commanders} Visit all the c-commanders of the current node, starting from the closest.
%
% \begin{forestexample}[tree bin=minipage,index={branch',c-commanded}]
%   \begin{forest} 
%     [VP
%       [DP[John]]
%       [V'
%         [V, draw, for c-commanded={draw,circle}
%           [sent]
%         ]
%         [DP[Mary]]
%         [DP[D[a]][NP[letter]]]
%       ]
%     ]
%   \end{forest}
% \end{forestexample}
%
% See how \indexex{branch'} is used to define |c-commanded|, and how \indexex{while nodewalk valid} and \indexex{nodewalk key>fake} are combined in the definition of |c-commanders|.
%    \begin{macrocode}
\forestset{
  define long step={c-commanded}{style}{branch'={siblings,descendants}},
  define long step={c-commanders}{style}{while nodewalk valid={parent}{siblings,fake=parent}},
}
%    \end{macrocode}
%
% |c-commanders| could also be defined using \indexex{branch}:
% \begin{lstlisting}
%   branch={current and ancestors, siblings}
% \end{lstlisting}
%
% \indexitem{node key>sn edges}
% 
% In linguistics, most people want the parent-child edge to go from the \emph{s}outh of the parent
% to the \emph{n}orth of the child.  This is achieved by this (badly named) style, which makes the
% entire (sub)tree have such edges.
%
% \begin{forestexample}
%   \begin{forest}
%     sn edges
%     [VP
%       [DP]
%       [V'
%         [V]
%         [DP]
%       ]
%     ]
%   \end{forest}
% \end{forestexample}
% 
%    \begin{macrocode}
\forestset{
  sn edges/.style={
    for tree={
      parent anchor=children, child anchor=parent
    }
  },
}
%    \end{macrocode}
%
% A note on implementation. Despite its name, this style does not refer to the |south| and |north|
% anchor of the parent and the child node directly.  If it did so, it would only work for trees with
% standard linguistic \index{grow}|=-90|.  So we rather use \FoRest;'s growth direction based
% anchors: \index{anchor>children} always faces the children and \index{anchor>parent} always faces
% the parent, so the edge will always be between them, and the normal, upward growing trees will
% look good as well.
%
% \begin{forestexample}[index={anchor>south,anchor>north,option>parent anchor,option>child anchor}]
%   \begin{forest}
%     [bad![VP,no edge, for tree={grow=90, edge=red},
%       for tree={parent anchor=south, child anchor=north} % bad
%     [DP][V'[V][DP]]]]
%   \end{forest}
%   \begin{forest}
%     [good![VP, no edge, for tree={grow=90, edge=green},
%                ~sn edges~                                 % good!
%     [DP][V'[V][DP]]]]
%   \end{forest}
% \end{forestexample}
%
% \indexitem{node key>roof}   Makes the edge to parent a triangular roof. 
%    \begin{macrocode}
\forestset{
  roof/.style={edge path'={%
      (.parent first)--(!u.children)--(.parent last)--cycle
    }
  },
}
%    \end{macrocode}
%
% \indexitem{node key>nice empty nodes}
%
% We often need empty nodes: tree (\ref{ex:niceemptynodes}a) shows how they look like by default:
% ugly.
%
% First, we don't want the gaps: we change the shape of empty nodes to coordinate.  We get tree
% (\ref{ex:niceemptynodes}b).
%
% Second, the empty nodes seem too close
% to the other (especially empty) nodes (this is a result of a small
% default |s_sep|).  We could use a greater \index{s sep}, but a better solution seems
% to be to use |calign=fixed_angles|.  The result is shown in (\ref{ex:niceemptynodes}c). 
%
% However, at the transitions from empty to non-empty nodes, tree (\ref{ex:niceemptynodes}c)
% seems to zigzag (although the base points of the spine nodes
% are perfectly in line), and the edge to the empty node left to VP
% seems too long (it reaches to the level of VP's base, while we'd
% prefer it to stop at the same level as the edge to VP itself).  The
% first problem is solved by substituting |fixed_angles| for
% |fixed_edge_angles|; the second one, by anchoring siblings of
% empty nodes at north.  Voilà, (\ref{ex:niceemptynodes}d)!
% 
% \begin{forestexample}[label=ex:niceemptynodes,layout=tree on bottom,index={fixed angles,fixed edge angles,calign,tree,delay,where option,content,for step,step>parent,step>children,option>anchor}]
%   \forestset{
%     xlist/.style={
%       phantom,
%       for children={no edge,replace by={[,append,
%           delay={content/.wrap pgfmath arg={\csname @alph\endcsname{##1}.}{n()+#1}}
%           ]}}
%     },
%     xlist/.default=0
%   }
%   \begin{forest}
%     [,~xlist~,
%     for tree={after packing node={s+=0.1pt}}, % hack!!!
%       [CP,                                                               %(a)
%         [][[][[][VP[DP[John]][V'[V[loves]][DP[Mary]]]]]]]
%       [CP, delay={where content={}{shape=coordinate}{}}                  %(b)
%         [][[][[][VP[DP[John]][V'[V[loves]][DP[Mary]]]]]]]
%       [CP, for tree={calign=fixed angles},                               %(c)
%            delay={where content={}{shape=coordinate}{}}
%         [][[][[][VP[DP[John]][V'[V[loves]][DP[Mary]]]]]]]
%       [CP, ~nice empty nodes~                                              %(d)
%         [][[][[][VP[DP[John]][V'[V[loves]][DP[Mary]]]]]]]
%     ]
%   \end{forest}
% \end{forestexample}
%
%    \begin{macrocode}
\forestset{
  nice empty nodes/.style={
    for tree={calign=fixed edge angles},
    delay={where content={}{shape=coordinate,
                            for current and siblings={anchor=north}}{}}
  },
}
%    \end{macrocode}
%    
%   \indexitem{node key>draw brackets}   Outputs the bracket representation of the tree.
%   \indexitem{node key>draw brackets compact}
%   \itemnosep
%   \indexitem{node key>draw brackets wide} These keys control whether the brackets have extra
%   spaces around them (|wide|) or not (|compact|).
%    \begin{macrocode}
\providecommand\text[1]{\mbox{\scriptsize#1}}
\forestset{
  draw brackets compact/.code={\let\drawbracketsspace\relax},
  draw brackets wide/.code={\let\drawbracketsspace\space},
  draw brackets/.style={
%    \end{macrocode}
% There's stuff to do both before (output the opening bracket and the content) and after (output the
% closing bracket) processing the children, so we use \indexex{for tree'}.
%    \begin{macrocode}
    for tree'={
      TeX={[%
%    \end{macrocode}
% Complication: \index{content format} must be expanded in advance, to correctly process tabular environments implicitely loaded by \index{align}|=|\index{value of=align>center}, which is the default in this library.  (Not that one would want a multiline output in the bracket representation, but it's better than crashing.)
%    \begin{macrocode}
        \edef\forestdrawbracketscontentformat{\foresteoption{content format}}%
      },
      if n children=0{
        TeX={\drawbracketsspace\forestdrawbracketscontentformat\drawbracketsspace}
      }{
        TeX={\textsubscript{\text{\forestdrawbracketscontentformat}}\drawbracketsspace}
      },
    }{
      TeX={]\drawbracketsspace},
    }
  },
  draw brackets wide
}
%    \end{macrocode}
% \end{syntax}
% 
% \subsubsection{GP1}
%
% \begin{syntax}
%   \indexitem{node key>GP1}
%   
% For Government Phonology (v1) representations. Here, the big trick
% is to evenly space $\times$s by having a large enough |outer_xsep|
% (adjustable), and then, before drawing (timing control option
% |before_drawing_tree|), setting |outer_xsep| back to 0pt.  The last step
% is important, otherwise the arrows between $\times$s won't draw!
%
% An example of an ``embedded'' |GP1| style:
% \begin{forestexample}[layout=tree on bottom,index={where option,tier,for step,step>children,content,tikz,option>l,dimen+,no edge},index>={!}]
%   \begin{forest}
%     myGP1/.style={
%       ~GP1~,
%       delay={where tier={x}{
%           for children={content=\textipa{##1}}}{}},
%       tikz={\draw[dotted](.south)--
%             (!1.north west)--(!l.north east)--cycle;},
%       for children={l+=5mm,no edge}
%     }
%     [VP[DP[John,tier=word,myGP1
%             [O[x[dZ]]]
%             [R[N[x[6]]]]
%             [O[x[n]]]
%             [R[N[x]]]
%     ]][V'[V[loves,tier=word,myGP1
%              [O[x[l]]]
%              [R[N[x[a]]]]
%              [O[x[v]]]
%              [R[N[x]]]
%              [O[x[z]]]
%              [R[N[x]]]
%     ]][DP[Mary,tier=word,myGP1
%            [O[x[m]]]
%            [R[N[x[e]]]]
%            [O[x[r]]]
%            [R[N[x[i]]]]
%     ]]]]
%   \end{forest}%
% \end{forestexample}
%
% And an example of annotations.
% \begin{forestexample}
%   \begin{forest}[,phantom,s sep=1cm
%     [{[ei]}, GP1
%       [R[N[x[A,~el~[I,~head~,~associate=N~]]][x]]]
%     ]
%     [{[mars]}, GP1
%       [O[x[m]]]
%       [R[N[x[a]]][x,~encircle~,densely dotted[r]]]
%       [O[x,~encircle~,~govern=<~[s]]]
%       [R,~fen~[N[x]]]
%     ]
%   ]\end{forest} 
% \end{forestexample}
%
%    \begin{macrocode}
\newbox\standardnodestrutbox
\setbox\standardnodestrutbox=\hbox to 0pt{\phantom{\forestOve{standard node}{content}}}
\def\standardnodestrut{\copy\standardnodestrutbox}
\forestset{
  GP1/.style 2 args={
    for n={1}{baseline},
    s sep=0pt, l sep=0pt,
    for descendants={
      l sep=0pt, l={#1},
      anchor=base,calign=first,child anchor=north,
      inner xsep=1pt,inner ysep=2pt,outer sep=0pt,s sep=0pt,
    },
    delay={
      if content={}{phantom}{for children={no edge}},
      for tree={
        if content={O}{tier=OR}{},
        if content={R}{tier=OR}{},
        if content={N}{tier=N}{},
        if content={x}{
          tier=x,content={$\times$},outer xsep={#2},
          for tree={calign=center},
          for descendants={content format={\noexpand\standardnodestrut\forestoption{content}}},
          before drawing tree={outer xsep=0pt,delay={typeset node}},
          s sep=4pt
        }{},
      },
    },
    before drawing tree={where content={}{parent anchor=center,child anchor=center}{}},
  },
  GP1/.default={5ex}{8.0pt},
  associate/.style={%
    tikz+={\draw[densely dotted](!)--(!#1);}},
  spread/.style={
    before drawing tree={tikz+={\draw[dotted](!)--(!#1);}}},
  govern/.style={
    before drawing tree={tikz+={\draw[->](!)--(!#1);}}},
  p-govern/.style={
    before drawing tree={tikz+={\draw[->](.north) to[out=150,in=30] (!#1.north);}}},
  no p-govern/.style={
    before drawing tree={tikz+={\draw[->,loosely dashed](.north) to[out=150,in=30] (!#1.north);}}},
  encircle/.style={before drawing tree={circle,draw,inner sep=0pt}},
  fen/.style={pin={[font=\footnotesize,inner sep=1pt,pin edge=<-]10:\textsc{Fen}}},
  el/.style={content=\textsc{\textbf{##1}}},
  head/.style={content=\textsc{\textbf{\underline{##1}}}}
}
%    \end{macrocode}
% \end{syntax}
%\iffalse
%</linguistics>
%\fi
%
%
%
%\iffalse
%<*edges>
%\fi
% \librarysection{edges}
%    \begin{macrocode}
\ProvidesForestLibrary{edges}[2016/12/05 v0.1.1]
%    \end{macrocode}
% 
% \begin{syntax}
% 
% \indexitem{node key>forked edge'}
%
%   Sets a forked edge to the current node.  Arbitrary growth direction and node rotation are
%   supported.
%
% \indexitem{node key>forked edge}
%
% Like \index{forked edge'}, but it also sets \index{option>parent anchor} and \index{option>child
% anchor} to the likely values of \index{anchor>children} and \index{anchor>parent}, respectively.
%
% \indexitem(tree){node key>forked edges}|=|\meta{nodewalk}
%
% Invokes \index{forked edge} for all nodes in the \meta{nodewalk}, by default the entire (sub)tree
% rooted in the current node.
%
% \indexitem{option>fork sep} The \index{forest cs>l}-distance between the parent anchor and the
% fork.
%   
% \end{syntax}
% 
% \begin{forestexample}[index={for step,tree,grow',forked edges}]
%   \begin{forest}
%     for tree={grow'=0,draw},
%     forked edges,
%     [/
%       [home
%         [saso
%           [Download]
%           [TeX]
%         ]
%         [alja]
%         [joe]
%       ]
%       [usr
%         [bin]
%         [share]
%       ]
%     ]
%   \end{forest}  
% \end{forestexample}
%
% See how growth direction based anchors \indexex{anchor>children} and \indexex{anchor>parent} are
% used in the definition below to easily take care of arbitrary \index{grow} and
% \index{rotate}.
%    \begin{macrocode}
\forestset{
  declare dimen={fork sep}{0.5em},
  forked edge'/.style={
    edge={rotate/.option=!parent.grow},
    edge path'={(!u.parent anchor) -- ++(\forestoption{fork sep},0) |- (.child anchor)},
  },
  forked edge/.style={
    on invalid={fake}{!parent.parent anchor=children},
    child anchor=parent,
    forked edge',
  },
  forked edges/.style={for nodewalk={#1}{forked edge}},
  forked edges/.default=tree,
}
%    \end{macrocode}
%
% \begin{syntax}
%   \indexitem{node key>folder} The children of the node are drawn like folders.
%
%   All growth directions are supported (well, cardinal directions work perfectly; the others await
%   the sensitivity of packing to \index{edge path}), as well as node rotation and \index{reversed}
%   order of children.
%
%   The outlook of the folder can be influenced by setting standard \foRest;'s options \index{l sep}
%   and \index{s sep} any time before packing, or \index{option>l} and \index{option>s} after
%   packing.  Setting \index{option>l} and \index{option>s} before packing will have no influence on
%   the layout of the tree.
%
%   \begin{syntax}
%     \indexitem(.45em){register>folder indent}|=|\meta{dimen}
%
%     Specifies the shift of the parent's side of the edge in the \index{forest cs>l}-direction.
%   \end{syntax}
%
% \end{syntax}
% 
% \begin{forestexample}[index={for step,tree,grow',folder}]
%   \begin{forest}
%     for tree={grow'=0,~folder~,draw}
%     [/
%       [home
%         [saso
%           [Download]
%           [TeX]
%         ]
%         [alja]
%         [joe]
%       ]
%       [usr
%         [bin]
%         [share]
%       ]
%     ]
%   \end{forest}
% \end{forestexample}
%    \begin{macrocode}
\forestset{
  declare dimen register=folder indent,
  folder indent=.45em,
  folder/.style={
    parent anchor=-children last,
    anchor=parent first,
    calign=child,
    calign primary child=1,
    for children={
      child anchor=parent,
      anchor=parent first,
      edge={rotate/.option=!parent.grow},
      edge path'/.expanded={
        ([xshift=\forestregister{folder indent}]!u.parent anchor) |- (.child anchor)
      },
    },
    after packing node={
      if n children=0{}{
        tempdiml=l_sep()-l("!1"),
        tempdims={-abs(max_s("","")-min_s("",""))-s_sep()},
        for children={
          l+=tempdiml,
          s+=tempdims()*(reversed()-0.5)*2,
        },
      },
    },
  }
}
%    \end{macrocode}
%\iffalse
%</edges>
%\fi
% \forestset{every index end/.style={}}
% \endinput
% Local Variables:
% mode: doctex
% TeX-command-default: "sty"
% fill-column: 100
% TeX-master: "forest"
% End: