我想画如下的树:
所需树显示 http://quicklatex.com/cache3/ql_c0f6b5397c19caf09ce70d6e47841eb7_l3.png
也就是说,我有交叉的边。树应该像普通树一样绘制(没有交叉),除了最后一层,其中叶子可以按任何水平顺序排列。节点等的数量是任意的,图像只是一个例子。
我对这棵树唯一了解的是 (a) 它的结构,即节点及其子节点,以及 (b) 每片叶子的排序号 (=x 位置),它决定了叶子应该在水平方向上显示的位置以形成交叉点。在上面的例子中,我知道的a1
是位置 0、b1
位置 1、a2
位置 2 和b2
位置 3。当我绘制特定的叶子时,我可以使用这些数字。
代码必须表示树的结构,如下所示:
\documentclass[a4paper]{scrartcl}
\usepackage{tikz}
\usepackage{tikz-qtree}
\begin{document}
\begin{tikzpicture}
\tikzset{frontier/.style={distance from root=70pt}}
\Tree [.Z [.\node{A};
\node{a1};
\node{a2}; ]
[.\node{B};
\node{b1};
\node{b2}; ] ]
\end{tikzpicture}
\end{document}
生成结果:
非交叉树显示http://quicklatex.com/cache3/ql_4217cf1d35018cf2016b55ac580d6085_l3.png
理想情况下,现在我想根据我所知道的排序号对叶子进行重新排序:
\Tree [.Z [.\node{A};
\node at (0,0) {a1};
\node at (2,0) {a2}; ]
[.\node{B};
\node at (1,0) {b1};
\node at (3,0) {b2}; ] ]
问题是,这会变成:
错误的树 http://quicklatex.com/cache3/ql_8b543330e2e251476b91100f13dcca4a_l3.png
问题:如何实现叶子的重新定位而不失去自动树布局功能tikz-qtree
?
一些背景知识:这些是由所谓的多重上下文无关语法递归生成的派生树,可以模拟 a^ib^ja^ib^j 等语言。我在终端后附加了数字,以便更明确地说明它们在重新排序后最终会出现在哪里。
答案1
你想要这样的东西吗?
请注意,我根本不确定我是否理解您要做什么。
在您对 Gonzalo Medina 的回答的评论中,您说您知道“a”必须出现在位置 0 和 2,而“b”必须出现在位置 1 和 3。但不清楚您希望如何实现自动化。(TeX 如何区分 1 个“a”和另一个“a”?您的示例代码中没有输入词“abab”,因此似乎没有以任何形式提供此信息。)
forest
允许您创建“动态”树,即您可以在各个阶段移动内容。在这里,我在计算树的布局之后但在绘制之前移动节点:
\documentclass[tikz,border=5pt]{standalone}
\usepackage{forest}
\begin{document}
\begin{forest}
for tree={
parent anchor=south,
child anchor=north,
where n children=0{
s sep=1.5em,
inner xsep=0pt
}{},
}
[Z
[A
[a1
]
[a2, before drawing tree={x+=1.5em}
]
]
[B
[b1, before drawing tree={x-=1.5em}
]
[b2
]
]
]
\end{forest}
\end{document}
编辑
OP 编辑了这个问题,以根据我上面的回答和评论中的讨论展示解决方案。但是,该解决方案需要手动指定叶节点的总数。我思考以下内容应避免此要求。想法是为每个叶节点增加一个 LaTeX 计数器,然后使用此计数器的最终值在绘制树之前调整节点的位置。leaf position
定义了一种新样式,它接受一个参数,该参数应该是节点在有序序列中的位置,即leaf position=2
如果叶子应该最终位于第三个(数字 2)位置。
\documentclass[tikz,border=5pt]{standalone}
\usepackage{forest}
\usepackage{calc}
\begin{document}
\begingroup
\newcounter{leafnodes}
\setcounter{leafnodes}{0}
\forestset{
leaf position/.style={
before drawing tree={
where n children=0{
x/.pgfmath={(#1-(.5*\theleafnodes)+.5)*1.5em}
}{},
}
},
}
\begin{forest}
for tree={
parent anchor=south,
child anchor=north,
where n children=0{
s sep=1.5em,
inner xsep=0pt,
delay={TeX={\stepcounter{leafnodes}}},
}{},
},
[Z
[A
[a1, leaf position=0
]
[a2, leaf position=2
]
]
[B
[b1, leaf position=1
]
[b2, leaf position=3
]
]
]
\end{forest}
\endgroup
\end{document}
编辑 编辑
为了回应评论中的讨论,这里有一个示例,它使用 将所有叶节点放在同一级别,tier=leaves
并将这些节点的高度设置为标准大小,以便从父节点绘制的边不会终止于不同的高度。我还将最左边的节点向左移动了一点,因为它在较大的树中看起来有点奇怪。显然,如果需要,可以进一步调整。
\documentclass[tikz,border=5pt]{standalone}
\usepackage{forest}
\usepackage{calc}
\begin{document}
\begingroup
\newcounter{leafnodes}
\setcounter{leafnodes}{0}
\forestset{
leaf position/.style={
before drawing tree={
where n children=0{
x/.pgfmath={(#1-(.5*\theleafnodes))*1.5em}
}{},
}
},
}
\begin{forest}
for tree={
parent anchor=south,
child anchor=north,
where n children=0{
s sep=1.5em,
inner xsep=0pt,
tier=leaves,
text height=5pt,
delay={TeX={\stepcounter{leafnodes}}},
}{},
},
[Z
[A
[A
[A
[T, leaf position=6
]
[y, leaf position=1
]
[e, leaf position=0
]
]
[a, leaf position=5
]
[a, leaf position=4
]
]
[a1, leaf position=8
]
[a2, leaf position=2
]
]
[B
[b1, leaf position=7
]
[b2, leaf position=3
]
]
]
\end{forest}
\endgroup
\end{document}
答案2
如果你愿意转向强大的forest
包,这可以轻松完成:
\documentclass[a4paper]{scrartcl}
\usepackage{forest}
\begin{document}
\begin{forest}
for tree={
parent anchor=south,
child anchor=north,
l sep=0.75cm
}
[Z,s sep=-40pt
[A,calign=fixed edge angles,calign primary angle=-30,calign secondary angle=60
[a1]
[a2]
]
[B,calign=fixed edge angles,calign primary angle=-60,calign secondary angle=30
[b1]
[b2]
]
]
\end{forest}
\end{document}
答案3
源自cfr的原始答案和评论:
\documentclass[tikz,border=5pt]{standalone}
\usepackage{forest}
\usepackage{calc}
\begin{document}
\begingroup
\def\f{1.5em} % scale
\def\n{4} % number of leaves
\def\xleaf#1{\f*(#1-\n/2+0.5)} % calculates x of a leaf
\begin{forest}
for tree={
parent anchor=south,
child anchor=north,
where n children=0{
s sep=1.5em,
inner xsep=0pt
}{},
}
[Z
[A
[a1, before drawing tree={x=\xleaf{0}}
]
[a2, before drawing tree={x=\xleaf{2}}
]
]
[B
[b1, before drawing tree={x=\xleaf{1}}
]
[b2, before drawing tree={x=\xleaf{3}}
]
]
]
\end{forest}
\endgroup
\end{document}
我想这就是它所能达到的极限了。虽然它需要叶子的总数,但我觉得从树中自动得出这个数字然后在表达式中使用它太复杂了before drawing tree
。
注意:cfr 的更新答案现在可以计算叶子了!