我正在绘制家谱,我想用级别和 ID 标记每个节点,最好在每个级别重新开始。我希望得到以下输出,然后自动编号。这个问题提供了一种枚举节点的方法,但我还想添加级别(理想情况下,每个级别都重新开始编号)。任何帮助都将不胜感激。
\usepackage{forest}
\begin{document}
\begin{forest}
for tree={
child anchor=south,
parent anchor=north,
grow'=north,
draw,
}
[1-1 A
[2-1 B
[3-1 C
]
[3-2 D
[4-1 E
]
[4-2 F
]
]
]
]
\end{forest}
\end{document}
答案1
首先,请注意。原帖所引述的问题是关于 TikZ 树的,而这个问题是关于 Forest 树的。因此答案完全不同。
我们将通过几个示例慢慢构建解决方案。如果您对解释不感兴趣,请直接跳到最后一段代码。
Forest 提供了有关节点级别(选项level
)和子节点编号(选项n
)的信息,这些信息可以以各种方式插入到内容中;最简单的方法可能是使用宏。下面,我们使用(表示附加)\forestoption
将此信息添加到内容的前面。请注意,我们必须用括号括住用于分隔标识符和其他内容的空格;如果我们不这样做,它将被键值解析机制“吃掉”。+content
content+
pgfkeys
\documentclass{standalone}
\usepackage{forest}
\begin{document}
\begin{forest}
for tree={
child anchor=south,
parent anchor=north,
grow'=north,
draw,
},
% We want to add to the content of the nodes (A, B, etc.),
% so we must "delay" the procedure to allow the content
% to be read in first.
delay={
for tree={
+content={\forestoption{level}-\forestoption{n}{ }},
% An alternative way of achieving the same, using the argument
% processor (.process):
% * grab an "O"ption (level)
% * grab another "O"ption (n), and
% * "w"rap the "two" options by macro "#1-#2{ }":
%
% +content/.process={OOw2}{level}{n}{#1-#2{ }},
},
},
[A
[B
[C]
[D
[E]
[F]
]
]
]
\end{forest}
\end{document}
从结果来看,我们发现 (a) Forest 从 0 开始对层进行编号(但我们希望根位于 1 层),并且 (b) 根子节点编号为 0(我们希望为 1)。这两个问题都很容易解决。对于 (a),我们只需将 1 添加到层,使用 eTeX 的\numexpr
:(\the\numexpr\forestoption{level}+1\relax
可扩展)执行此操作。对于根,如果我们手动处理它是最简单的。
\documentclass{standalone}
\usepackage{forest}
\begin{document}
\begin{forest}
for tree={
child anchor=south,
parent anchor=north,
grow'=north,
draw,
},
delay={
% Take care of the root manually:
+content={1-1\space},
% We use "for descendants" instead of "for tree" now,
% so that we avoid visiting the root.
for descendants={
+content={\the\numexpr\forestoption{level}+1\relax-\forestoption{n}{ }},
},
},
[A
[B
[C]
[D
[E]
[F]
]
]
]
\end{forest}
\end{document}
这样就生成了 OP 所要求的树,但一般情况下它不起作用。如果节点也C
有两个子节点(例如G
和),它们将获得与节点和:和相同的标识符。显然,如果同一级别但属于不同父节点的节点要获得不同的 ID,我们就不能将子节点编号用作ID 的一部分。H
E
F
4-1 G
4-2 H
n
下面的想法是像往常一样遍历树(使用for tree
,因为不需要对根进行特殊处理),并分别记住每个级别的最后访问节点的 ID(我们将使用一些低级 TeX 构造来执行此操作)。我们将这些“级别 ID”存储在名为 的控制序列中leveln<level number>
。为了引用它们,我们定义一个辅助宏,\leveln
将其扩展到当前节点的级别 ID 控制序列名称(leveln\forestoption{level}
),然后使用\csname\leveln\endcsname
来访问级别 ID 的值,或(etoolbox
)\csedef{\leveln}{...}
来(重新)定义该值。
\documentclass{standalone}
\usepackage{forest}
\usepackage{etoolbox}
\begin{document}
% This produces the control sequence *name* of the counter for the current
% node's level; the idea is to use it in "\csname\leveln\endcsname" and such.
\def\leveln{leveln\forestoption{level}}
\begin{forest}
for tree={
child anchor=south,
parent anchor=north,
grow'=north,
draw,
},
delay={
for tree={
% Step the level ID counter by one, or set it to 1 if it is not yet
% defined. The latter works because when "\csname\leveln\endcsname" is
% not yet defined, it comes out meaning "\relax" (delimiting the end of
% the numeric expression), so we are evaluating "1+0"; and if it is
% defined, say having value 42, then we are evaluating the numeric
% expression 1+042, which is again what we want.
TeX={\csedef{\leveln}{\the\numexpr1+0\csname\leveln\endcsname}},
% Prepend to the content. We need to expand the prefix right away,
% because the value of "\csname\leveln\endcsname" is going to
% change way before the node is typeset.
+content/.expanded={%
% the level number, plus one
\the\numexpr\forestoption{level}+1\relax
% a dash and the level ID
-\csname\leveln\endcsname
% the space
{ }%
},
},
},
[A
[B
[C
[E]
[F]
]
[D
[G]
[H]
]
]
]
\end{forest}
\end{document}