我需要画一棵树,不断使用 dotty 并添加 PNG 开始变得很麻烦。有没有办法让 LaTeX 自己画树,而不需要学习 TikZ 这样的全新语言?
答案1
虽然我通常会同意 Will Robertson 的评论,但因为 TikZ是非常棒,值得学习,但我认为 TikZ 对于这种情况来说有点过头了。我个人认为它的树规范语法过于繁琐。我更喜欢使用qtree 包(即在 CTAN 上,并且显然包含在 TeX Live 和 MikTeX 中)。该包使用起来非常简单。考虑以下 TeX:
\Tree[.IP [.NP [.Det \textit{the} ]
[.N\1 [.N \textit{package} ]]]
[.I\1 [.I \textsc{3sg.Pres} ]
[.VP [.V\1 [.V \textit{is} ]
[.AP [.Deg \textit{really} ]
[.A\1 [.A \textit{simple} ]
\qroof{\textit{to use}}.CP ]]]]]]
这将生成以下树:
就这些!最棒的是,TeX 描述读就像树一样。我可以看一眼 TeX,然后立即知道创建的树会是什么样子。基本语法很简单; ,它绘制三角形,需要在末尾添加其节点名称。 只是数学模式素数的快捷方式。此外,qtree 也将始终将和渲染为下标和上标。(除非您关闭此功能。)[.node-name subtrees... ]
\qroof
\1
_
^
一般来说,您可以在开头 ( [.+ 1 [.* 2 3 ]]
) 或结尾 ( [ 1 [ 2 3 ].* ].+
) 提供节点名称;您甚至可以在两个地方都提供节点名称,但它们必须匹配(这并不奇怪)。顺便说一句,这就是为什么它\qroof
以这种方式获取节点名称的原因。您甚至可以完全不提供节点名称,以获得具有平滑连接的节点。如果其中有任何不清楚的地方,请查看手册。
现在,qtree 原样有一个缺点,即它是为简单的树。它确实提供了有限的支持来改变节点间距、框架树的各个部分以及诸如此类的事情,但它无法做任何非常花哨的事情。但幸运的是,如果你想要的话,你仍然可以得到它:输入tikz-qtree。此包允许您充分利用 TikZ 的全部功能来绘制树。两个明显的功能是:(a)树中的标签可以是任意的,而不是文本\node
;(b)您可以重新定义它如何绘制边缘以获得箭头、虚线、弯曲边缘等。但它的功能远不止于此:如果您将嵌入\Tree
到 TikZ 图片中,您可以这样做任何您想要对节点进行的操作,例如圈出它们、在它们之间绘制箭头以进行转换等。
也许你现在不需要这种能力,但关键信息是使用 qtree惯于将您锁定在简单的树中。如果您决定想要更强大的树,您需要做的就是更改一个导入;一切都会继续按原样工作,但您也会获得更多功能。我不确定 tikz-qtree 是否真的在后台使用了 qtree,但无论如何,所有的句法因为 qtree 仍然有效,并且输出是相同的,至少据我所知。
(PS:语言学家,请原谅/纠正上面树中的任何错误;距离我的句法课程已经过去了一两年了。)
答案2
我将代表 提出请求forest
。虽然forest
非常灵活和强大,但使用起来也非常简单。像 一样qtree
,它使用简单、简洁的语法,‘读起来像一棵树’,但我发现 的forest
语法更容易学习。(但是,这可能是因为我qtree
先学的。)像 一样tikz-qtree
,它为您提供了 TikZ 的所有功能,但是与 不同的是qtree
,您不必更改包即可使用该功能,因为forest
下面已经在使用 TikZ。此外,除了 TikZ 的所有功能之外,您还可以拥有forest
其自身的所有功能。而且这非常重要:强大、专门的支持,可以手动、自动和/或动态绘制各种树。查看此站点上的示例以了解各种可能性。
然而,对于简单的树来说,forest
非常简单。
这个答案由两部分组成。第一部分适用于当前版本forest
(版本 2)。第二部分是我原来的答案,适用于早期版本forest
(版本 1)。变化不是很大,但是,如果您是该软件包的新手,如果您阅读适用于您正在使用的版本的部分而不进行修改,您会发现更容易理解。
当前forest
版本:第 2 版
这是forest
发布于的树的代码版本Antal SZ 的回答。
\documentclass[tikz,border=10pt]{standalone}
\usepackage[linguistics]{forest}
\begin{document}
\begin{forest}
[IP
[NP
[Det
[\textit{the}]
]
[N$'$
[N
[\textit{package}]
]
]
]
[I$'$
[I
[\textsc{3sg.Pres}
]
]
[VP
[V$'$
[V
[\textit{is}]
]
[AP
[Deg
[\textit{extremely}]
]
[A$'$
[A
[\textit{straightforward}]
]
[CP
[\textit{to wield}, roof]
]
]
]
]
]
]
]
\end{forest}
\end{document}
基本思想是将树中的每个节点括在方括号中。节点的子树(如果有)也包含在同一个括号中。
请注意,分支点没有点,并且结束方括号前不需要留空格。事实上,上面的代码相当于
\begin{forest}
[IP[NP[Det[\textit{the}]][N$'$[N[\textit{package}]]]][I$'$[I[\textsc{3sg.Pres}]][VP[V$'$[V[\textit{is}]][AP[Deg[\textit{extremely}]][A$'$[A[\textit{straightforward}]][CP[\textit{to wield}, roof]]]]]]]]
\end{forest}
显然,这根本不容易阅读——因此我更喜欢留出大量“不必要的”空间。
forest
然而,不能容忍空行,因此必须避免。
上述树产生以下输出:
如何将树变成括号规范forest
用途
从根开始并将其放在forest
环境内和方括号内:
\begin{forest}
[IP% root
% rest of tree will go here
]
\end{forest}
树的其余部分由一棵或多棵较小的树组成。这些是根节点的子树。在本例中,我们有 2 棵子树,因此我们从每棵子树的根开始,并将它们分别添加到各自的方括号中。
\begin{forest}
[IP% root
[NP% root of subtree
% rest of subtree will go here
]
[I$'$% root of subtree
% rest of subtree will go here
]
]
\end{forest}
然后您可以依次对每个子树进行操作并重复该操作。
特殊款式
因为我们对语言学树中的这个问题感兴趣,所以我linguistics
在加载包时添加了这个选项。
\usepackage[linguistics]{forest}
这会做两件事:(1)加载linguistics
库,使语言学中的各种使用风格可用(例如roof
上面使用的);(2)改变树的默认外观。
如果我们只希望一些树使用库的默认值(也许我们的一些树是语言学树,一些是其他类型的树),我们可以使用
\usepackage{forest}
\useforestlibrary{linguistics}
在序言中。然后我们可以使用
\forestapplylibrarydefaults{linguistics}
在文档主体中的本地 TeX 范围内,将默认值仅应用于选定的树。例如,
{\forestapplylibrarydefaults{linguistics}
\begin{forest}
<specification 1>
\end{forest}}
\begin{forest}
<specification 2>
\end{forest}
会将lingustics
默认值应用于 给出的树,<specification 1>
但不应用于 给出的树<specification 2>
。
但我们暂时假设当前文档中的所有树都是语言树。
为了制作三角形屋顶,我们只需添加, roof
到适当的节点并forest
应用其三角形屋顶样式。
如果你以后想制作更复杂的树,也可以以同样的方式使用 TikZ 样式。, text=red
例如,添加到节点会将节点的文本变为红色。
[N$'$, text=red
[N
[\textit{package}]
]
]
条件样式可节省输入
如果愿意,您还可以保存更改每个终端节点的字体。如果大多数终端节点应该用斜体表示,您可以说
if n children=0{% if the node doesn't have any children of its own
font=\itshape
}{},
要将此条件应用于整个树,从而将斜体应用于所有终端节点,我们可以说
for tree={
if n children=0{
font=\itshape
}{},
}
\begin{forest}
在指定树本身之后和之前。这被称为前言树的。
, font=\scshape
然后,您可以通过在指定节点的内容后说出来为单个小型大写字母节点覆盖此功能。
修订树的完整代码
\documentclass[tikz,border=10pt]{standalone}
\usepackage[linguistics]{forest}
\begin{document}
\begin{forest}
for tree={
if n children=0{
font=\itshape
}{},
}
[IP
[NP
[Det
[the]
]
[N$'$
[N
[package]
]
]
]
[I$'$
[I
[3sg.Pres, font=\scshape]
]
[VP
[V$'$
[V
[is]
]
[AP
[Deg
[extremely]
]
[A$'$
[A
[straightforward]
]
[CP
[to wield, roof]
]
]
]
]
]
]
]
\end{forest}
\end{document}
选定的附加功能
语言学家对树的要求的一个共同特征似乎是确保终端节点对齐。
forest
允许您指定节点应在公共的 上对齐tier
。要使用此功能,您只需, tier=<name of tier>
在指定节点的内容后写入。
这是一个极端的例子:
\begin{forest}
for tree={
fit=band,% spaces the tree out a little to avoid collisions
}
[things
[cabbages, tier=vegetables
[peaches, tier=fruits]
]
[kings, tier=aristocrats]
[sealing wax
[queens, tier=aristocrats
[carrots, tier=vegetables]
[pineapple, tier=fruits]
[aubergine, tier=vegetables]
]
]
]
\end{forest}
在我们的语言学家树中,我们只希望终端节点对齐。我们已经说过我们希望它们以斜体显示,因此我们可以在那里添加层级规范。
我们确实有
for tree={
if n children=0{
font=\itshape
}{},
}
现在我们将其改为以下内容:
for tree={
if n children=0{
font=\itshape,
tier=terminal,
}{},
}
树发生了显著的变化:
早期forest
版本:版本 1
这是forest
发布于的树的代码版本Antal SZ 的回答。
\documentclass[tikz,border=10pt]{standalone}
\usepackage{forest}
\begin{document}
\begin{forest}
[IP
[NP
[Det
[\textit{the}]
]
[N$'$
[N
[\textit{package}]
]
]
]
[I$'$
[I
[\textsc{3sg.Pres}
]
]
[VP
[V$'$
[V
[\textit{is}]
]
[AP
[Deg
[\textit{extremely}]
]
[A$'$
[A
[\textit{straightforward}]
]
[CP
[\textit{to wield}, triangle]
]
]
]
]
]
]
]
\end{forest}
\end{document}
基本思想是将树中的每个节点括在方括号中。节点的子树(如果有)也包含在同一个括号中。
请注意,分支点没有点,并且结束方括号前不需要留空格。事实上,上面的代码相当于
\begin{forest}
[IP[NP[Det[\textit{the}]][N$'$[N[\textit{package}]]]][I$'$[I[\textsc{3sg.Pres}]][VP[V$'$[V[\textit{is}]][AP[Deg[\textit{extremely}]][A$'$[A[\textit{straightforward}]][CP[\textit{to wield}, triangle]]]]]]]]
\end{forest}
显然,这根本不容易阅读——因此我更喜欢留出大量“不必要的”空间。
forest
然而,不能容忍空行,因此必须避免。
上述树产生以下输出:
如何将树变成括号规范forest
用途
从根开始并将其放在forest
环境内和方括号内:
\begin{forest}
[IP% root
% rest of tree will go here
]
\end{forest}
树的其余部分由一棵或多棵较小的树组成。这些是根节点的子树。在本例中,我们有 2 棵子树,因此我们从每棵子树的根开始,并将它们分别添加到各自的方括号中。
\begin{forest}
[IP% root
[NP% root of subtree
% rest of subtree will go here
]
[I$'$% root of subtree
% rest of subtree will go here
]
]
\end{forest}
然后您可以依次对每个子树进行操作并重复该操作。
特殊款式
为了制作三角形屋顶,我们只需添加, triangle
到适当的节点并forest
应用其三角形根样式。
如果你以后想制作更复杂的树,也可以以同样的方式使用 TikZ 样式。, text=red
例如,添加到节点会将节点的文本变为红色。
[N$'$, text=red
[N
[\textit{package}]
]
]
逻辑学家和语言学家的分支
即使是简单的逻辑学家和语言学家的树也可能需要一些样式才能看起来正确。特别是,树通常具有从父节点下方的公共点开始并延伸到子节点上方的点的分支。虽然这不是默认的,但我们可以通过以下方式实现它:
parent anchor=south,% start branches beneath the parent
child anchor=north,% end branches above the child
要将其应用于整棵树,我们可以说
\begin{forest}
for tree={
parent anchor=south,
child anchor=north,
}
[IP
...
]
\end{forest}
条件样式可节省输入
如果愿意,您还可以保存更改每个终端节点的字体。如果大多数终端节点应该用斜体表示,您可以说
if n children=0{% if the node doesn't have any children of its own
font=\itshape
}{},
, font=\scshape
然后,您可以通过在指定节点的内容后说出来为单个小型大写字母节点覆盖此功能。
修订树的完整代码
\documentclass[tikz,border=10pt,multi]{standalone}
\usepackage{forest}
\begin{document}
\begin{forest}
for tree={
parent anchor=south,
child anchor=north,
if n children=0{
font=\itshape
}{},
}
[IP
[NP
[Det
[the]
]
[N$'$
[N
[package]
]
]
]
[I$'$
[I
[3sg.Pres, font=\scshape]
]
[VP
[V$'$
[V
[is]
]
[AP
[Deg
[extremely]
]
[A$'$
[A
[straightforward]
]
[CP
[to wield, triangle]
]
]
]
]
]
]
]
\end{forest}
\end{document}
选定的附加功能
语言学家对树的要求的一个共同特征似乎是确保终端节点对齐。
forest
允许您指定节点应在公共的 上对齐tier
。要使用此功能,您只需, tier=<name of tier>
在指定节点的内容后写入。
这是一个极端的例子:
\begin{forest}
for tree={
parent anchor=south,
child anchor=north,
fit=band,% spaces the tree out a little to avoid collisions
}
[things
[cabbages, tier=vegetables
[peaches, tier=fruits]
]
[kings, tier=aristocrats]
[sealing wax
[queens, tier=aristocrats
[carrots, tier=vegetables]
[pineapple, tier=fruits]
[aubergine, tier=vegetables]
]
]
]
\end{forest}
在我们的语言学家树中,我们只希望终端节点对齐。我们已经说过我们希望它们以斜体显示,因此我们可以在那里添加层级规范。
我们确实有
for tree={
parent anchor=south,
child anchor=north,
if n children=0{
font=\itshape
}{},
}
现在我们将其改为以下内容:
for tree={
parent anchor=south,
child anchor=north,
if n children=0{
font=\itshape,
tier=terminal,
}{},
}
树发生了显著的变化:
答案3
对于简单的、非“图形”的树,您可以使用以下dirtree
包:
\documentclass{article}
\usepackage{dirtree}
\begin{document}
\dirtree{%
.1 debug.
.2 filename.
.2 modules.
.3 module.
.3 module.
.3 module.
.2 level.
}
\end{document}