我感兴趣的是使用 TikZ 绘制有根树,这些树的叶子应该都在同一水平,就像这样:
请不要关注花哨的样式和颜色,我只希望所有叶子都处于同一水平。有人知道怎么做吗?我查看了手册和Texample 上的相应部分,但目前为止还没有运气。
更新:在这个问题得到回答后不久,我发现了LaTeX newicktree 包,它允许您以极其简单的方式绘制此类树,只需以系统发育学中人们已经使用的格式指定它们即可。这显然比求助于 TikZ 要简单得多,但还是要感谢所有帮助我的人。
答案1
如果您准备告诉 TikZ 顶部标签的顺序,这里有一个替代方案。这有点笨拙,尤其是它会绘制多条线两次(或更多!)。另外,我相信了你的话,忽略了花哨的样式。
\documentclass{minimal}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}[rotate=45]
\begin{scope}[rotate=45]
\node[coordinate] (start) at (0,0) {};
\xdef\pl{start}
\foreach \n/\l in {
rayfinned fish/rf,
lungfish/lf,
salamanders/sa,
frogs/fr,
turtles/tt,
lizards/lz,
snakes/sn,
crocodiles/cr,
birds/bd,
mammals/mm%
} {
\node[transform shape,below right] (\l) at (\pl.south west) {\n};
\xdef\pl{\l}
}
\end{scope}
\foreach \a/\b in {
rf/mm,
lf/mm,
sa/mm,
sa/fr,
tt/mm,
lz/mm,
lz/sn,
lz/bd,
cr/bd%
} {
\draw (\a.mid west) |- (\b.mid west);
}
\end{tikzpicture}
\end{document}
得出的结果为:
工作原理说明
首先要理解的是旋转。此代码使用特定类型的路径绘制线条,该路径被限制为仅水平和垂直。然而,在期望的结果中,线条是对角线。解决方案:旋转图片,使对角线为内部的“水平”和“垂直”。
要理解的第二件事是双倍的旋转。外部旋转(在
tikzpicture
环境上)处理对角线到水平和垂直线的转换。第二次旋转(在第一个上scope
)是让节点指向上方。为了正确执行此操作,我们将键添加transform shape
到实际节点。这意味着节点相对于该范围之外的所有内容旋转 45 度。现在进行节点定位。我们在 (0,0) 处定义起始坐标 (
start
)。然后我们循环遍历节点,将设置\n
为节点内容并\l
作为该节点(其标签)的简写。该宏\pl
保存以前的节点,在第一次迭代时设置为起始坐标。我们希望节点排列整齐,看起来像一个排列整齐的列表。为了实现这一点,我们将西北当前节点的锚点西南前一个节点的锚点。below right
节点上的键表示“使用西北锚点定位此节点”,而(\pl.south west)
表示“将其放置在前一个节点的西南锚点”。最后,我们将设置为\pl
当前节点的标签,该节点将成为下一次迭代中的下一个节点(请注意\xdef
,如果我们使用\edef
它,它将是迭代的本地节点,这不是我们想要的)。最后,画线。我们循环遍历连接的对,从
mid west
一个节点的锚点到mid west
另一个节点的锚点画一条线。我们首先用“上部”节点指定对,然后画一条先“垂直”然后“水平”的线(记住,在最终渲染中,这些线将旋转到对角线)。使用锚点mid west
意味着线条将在基线上方半处结束ex
。由于我们的线条定义非常严格,因此有时我们画在另一条线上方的事实应该不会太明显。
答案2
好问题!TikZ 不是为制作这种树而设置的。它假设每个子节点的位置是子节点数量和子节点总数的函数。用每个叶子都有一个子节点来定义树是行不通的,因为当你添加哺乳动物的叶子时,鳍鱼的叶子需要离根更远。
但您可以通过在常规点处创建不可见节点来欺骗它。我认为您的树需要有 10 层深。
或者,您可以使用自定义增长函数进行破解(参见 PGF 2.00 手册第 42 节或 2.10 手册第 53 节):
\begin{tikzpicture}[%
grow via three points={%
one child at (-0.5,1) and two children at (-0.5,1) and (0.5,1)},
genus/.style={
rectangle,inner sep=0pt,outer sep=1pt, minimum width=5pt,minimum height=5pt,fill,
label={[black,anchor=west,rotate around={90:(-2.5pt,0)}
]0:#1}},
]
\node[coordinate] {} [%
grow via three points={one child at (0,0) and two children at (-4.5,9) and (0.5,1)},
very thick,yellow
]
child {node[genus=rayfinned fish] {}}
child {
[grow via three points={one child at (0,0) and two children at (-4,8) and (0.5,1)}]
child {node[genus=lungfish] {}}
child {
[grow via three points={one child at (0,0) and two children at (-3,6) and (1,2)}]
child {
[grow via three points={one child at (0,0) and two children at (-0.5,1) and (0.5,1)}]
child {node[genus=salamanders] {}}
child {node[genus=frogs] {}}
}
child[blue] {
[grow via three points={one child at (0,0) and two children at (-2.5,5) and (0.5,1)}]
child {node[genus=turtles] {}}
child {
[grow via three points={one child at (0,0) and two children at (-0.5,1) and (2,4)}]
child {
[grow via three points={one child at (0,0) and two children at (-1,2) and (1,2)}]
child {
[grow via three points={one child at (0,0) and two children at (-0.5,1) and (0.5,1)}]
child {node[genus=lizards] {}}
child {node[genus=snakes] {}}
}
child {
[grow via three points={one child at (0,0) and two children at (-0.5,1) and (0.5,1)}]
child {node[genus=crocodiles] {}}
child {node[genus=birds] {}}
}
}
child {node[genus=mammals] {}}
}
}
}
}
;
\end{tikzpicture}
这可能应该被清理——我认为你可以在每个方向和尺度上创建一个命名坐标。
答案3
我发现这个答案在官方邮件列表中。据我所知,这是一种与此处提出的方法不同的方法,但至少问题是相同的。尽管如此,我还是可以重现所需的结果。但它可能对某些人有用,所以我想在这里链接它。
还有另一个有用的提示并没有回答这个问题:如果您使用 PStricks,您可以使用命令\skiplevel
。