我经常要画如下这样的图:
我想使用tikz-qtree
,因为我有很多树,这个包大大简化了事情。现在我使用以下代码,因为不可能在节点中拥有节点并使tikz-qtree
树元素成为节点。所以我使用来自的网格代码如何在 TikZ 中自动按网格显示坐标?并从绝对位置到其他绝对位置绘制线条。这很耗时,而且看起来总是不对,字体大小改变时我必须重做。有没有更好的方法?
\documentclass{minimal}
\usepackage{tikz-qtree}
\tikzset{every roof node/.append style={inner sep=0.1pt,text height=2ex,text depth=0.3ex}}
\newcommand{\sliste}[1]{%
\mbox{%
$\left\langle\mbox{\scshape #1}\right\rangle$}%
}
\begin{document}
\begin{tikzpicture}
\tikzset{level 1+/.style={level distance=3\baselineskip}}
\tikzset{frontier/.style={distance from root=12\baselineskip}}
%\draw (-3,-5) to[grid with coordinates] (4,0);
\Tree[.S
[.{V \sliste{ S$\!/\!/$V }}
[.V liest$_k$ ] ]
[.{S$\!/\!/$V}
[.NP Jens ]
[.{V$'$$\!/\!/$V}
[.NP \edge[roof]; {das Buch} ]
[.{V$\!/\!/$V} \_$_k$ ] ] ] ]
\draw[semithick,<->,color=green] (3.1,-3.9) ..controls +(south east:.5) and +(south west:.5)..(2.7,-3.9);
\draw[semithick,<->,color=green] (3.5,-3.7) ..controls +(east:.5) and +(east:.5)..(2.8,-2.5);
\draw[semithick,<->,color=green] (2.8,-2.3) ..controls +(east:.5) and +(east:.5)..(1.7,-1.1);
\draw[semithick,<->,color=green] (1.5,-0.9) ..controls +(north:.5) and +(north:.5)..(-0.8,-0.9);
\draw[semithick,<->,color=green] (-0.7,-1.1) ..controls +(south east:.2) and +(north east:.5)..(-1.0,-2.4);
\end{tikzpicture}
\end{document}
编辑:
我遵循建议并使用了tikzmark
和\subnode
:
\documentclass{minimal}
\usepackage{tikz-grid}
\usepackage{tikz-qtree}
\tikzset{every roof node/.append style={inner sep=0.1pt,text height=2ex,text depth=0.3ex}}
\usetikzlibrary{tikzmark}
\newcommand{\sliste}[1]{%
\mbox{%
$\left\langle\mbox{\scshape #1}\right\rangle$}%
}
\begin{document}
\begin{tikzpicture}
\tikzset{level 1+/.style={level distance=3\baselineskip}}
\tikzset{frontier/.style={distance from root=12\baselineskip}}
\Tree[.S
[.{V \sliste{ S$/\!/$\subnode{vcomp}{V} }}
[.{\subnode{vliest}{V}} liest$_k$ ] ]
[.{S$/\!/$\subnode{vs}{V}}
[.NP Jens ]
[.{V$'$$\!/\!/$\subnode{vbar}{V}}
[.NP \edge[roof]; {das Buch} ]
[.{\subnode{vzero}{V}$\!/\!/$\subnode{vdsl}{V}} \_$_k$ ] ] ] ]
\draw[semithick,<->,color=green] (vcomp.east) ..controls +(south east:.2) and +(north east:.5)..(vliest.east);
\end{tikzpicture}
\end{document}
结果很有趣:如果我使用pdflatex
AUX 文件,并且没有 AUX 文件,它就会工作。只要有 AUX 文件,代码就会生成两个页面,或者箭头会分布在页面上。嗯。
编辑2:
我按照 Allen Mun 的建议进一步研究了类似的例子:
\documentclass{minimal}
\usepackage{tikz-grid}
\usepackage{tikz-qtree}
\tikzset{every roof node/.append style={inner sep=0.1pt,text height=2ex,text depth=0.3ex}}
\usetikzlibrary{tikzmark}
\newcommand{\sliste}[1]{%
\mbox{%
$\left\langle\mbox{\scshape #1}\right\rangle$}%
}
\newcommand{\trace}{\raisebox{0.2ex}{\_}\rule{0cm}{0.7em}}
\begin{document}
\begin{tikzpicture}[
level 1+/.style={level distance=3\baselineskip},
frontier/.style={distance from root=15\baselineskip},
connect/.style={semithick,<->,color=green}]
\Tree[.S
[.\node (NP) {NP}; \edge[roof]; {das Buch} ]
[.\node (S/NP) {S/NP};
[.{V \sliste{ S/$\!$/V }}
[.V liest$_k$ ] ]
[.\node (S//V/NP) {S$/\!/$V/NP};
[.\node (NP/NP) {NP/NP}; \trace{} ]
[.{V$'$$\!/\!/$V}
[.NP Jens ]
[.{V$\!/\!/$V} \_$_k$ ] ] ] ] ] ]
\draw[connect] (NP/NP) [bend right] to (S//V/NP.south east);
\draw[connect] (S//V/NP.north east) [bend right] to (S/NP.east);
\draw[connect] (S/NP.north east) [bend right] to (NP);
\end{tikzpicture}
\end{document}
此图的意图是显示 NP 信息是共享的。因此,如果能够直接连接到 NP 节点,那就太好了。
答案1
即使forest
它可以自动完成很多事情,也需要一定程度的手动调整。它根本无法知道节点的内容方法。但是,forest
确实允许您将循环集成到树中,这在某些情况下可能很有吸引力。
例如:
\documentclass[tikz,border=5pt]{standalone}
\usetikzlibrary{tikzmark, arrows.meta, bending}
\usepackage{forest}
\begin{document}
\tikzset{
connect/.style={{Stealth[bend]}-{Stealth[bend]}, draw=green, shorten <=-3pt, shorten >=-3pt}
}
\newlength\txtht
\settoheight\txtht{B}
\begin{forest}
for tree={
parent anchor=south,
child anchor=north,
if n children=0{tier=t, text height=\txtht}{},
},
[S
[NP, tikz={\draw [connect] (.north east) [bend left] to ([xshift=-10pt]np1.north east);}
[das Buch, triangle]
]
[S/NP, name=np1, tikz={\draw [connect] (.east) [bend left] to ([xshift=-10pt]np2.north east);}
[V (S//V), tikz={\draw [connect] ([xshift=-10pt].south east) [bend left] to (v1.north east);}
[V, name=v1
[liest$_k$]
]
]
[S//V/NP, name=np2
[NP/NP, tikz={\draw [connect] (.east) [bend right] to ([xshift=-10pt]np2.south east);}
[-]
]
[V$'$//V, tikz={\draw [connect] (.east) [bend left] to ([xshift=-5pt]v2.north east);}
[NP
[Jens]
]
[V//V, name=v2, tikz={\draw [connect] ([xshift=5pt].south west) [out=-105, in=-75] to ([xshift=-5pt].south east);}
[${}_{-k}$]
]
]
]
]
]
\end{forest}
\end{document}
答案2
没必要这么复杂。任何tikz-qtree
节点标签都可以是显式的 TikZ\node
命令,因此您可以命名节点而无需做太多额外工作。我还对箭头使用了更简单的语法,这样您就不需要指定控件(我认为这也使箭头变得更美观)。即使是较小的箭头也不需要子节点,因为它们可以用键缩短shorten
(如示例中的 V//V 箭头)。
正如 Qrrbrbirlbel 所说,使用该forest
包可以使这个过程稍微容易一些,因为它允许您简单地为任何节点指定一个标签而无需使用明确的\node
命令,但除此之外基本过程是相同的。
\documentclass{article}
\usepackage{tikz-qtree}
\tikzset{every roof node/.append style={inner sep=0.1pt,text height=2ex,text depth=0.3ex}}
\newcommand{\sliste}[1]{%
\mbox{%
$\left\langle\mbox{\scshape #1}\right\rangle$}%
}
\begin{document}
\begin{tikzpicture}[
level 1+/.style={level distance=3\baselineskip},
frontier/.style={distance from root=12\baselineskip},
connect/.style={semithick,<->,color=green}]
\Tree[.S
[.\node (V1) {V \sliste{ S$\!/\!/$V }};
[.\node(V){V}; liest$_k$ ] ]
[.\node (S/V) {S$\!/\!/$V};
[.NP Jens ]
[.\node(V'V) {V$'$$\!/\!/$V};
[.NP \edge[roof]; {das Buch} ]
[.\node(V/V) {V$\!/\!/$V}; \_$_k$ ] ] ] ]
\draw[connect,shorten >=.5em,shorten <=.5em] (V/V.south east) [bend left] to (V/V.south west) ;
\draw[connect] (V/V.north east) [bend right] to (V'V.east);
\draw[connect] (V'V.north east) [bend right] to (S/V.east);
\draw[connect,shorten <=.5em] (S/V.north east) to [bend right] (V1) ;
\draw[connect] (V1) to [bend left] (V);
\end{tikzpicture}
\end{document}