我想在 TikZ 中重现以下类似邻接路径的邻接树,我只能手工绘制。请参见此处:
第一分钟:我的最小工作示例 (MWE) 使用tikz-dependency
Success 仅生成文本,而不是路径,因为箭头始终指向单元格。这对于依赖关系树来说完全没问题,并且该包非常适合此目的,但我在这里需要一些不同的东西。
欢迎任何其他想法,但不一定与此方案一致。
\documentclass{standalone}
\usepackage{tikz}
\usepackage{tikz-dependency}
\begin{document}
\begin{dependency}
\begin{deptext}[column sep=1em]
the \& girl \& for \& wh- \& om \& the \& man \& bought \& the \& book\\
A \& O \& U \& U \& O \& A \& O \& I \& A \& O\\
\end{deptext}
\end{dependency}
\end{document}
我不知道如何绘制这样的路径tex-dependency
,只有指向单词的箭头。
第二轮我尝试使用forest
then,但无法产生令人满意的结果。代码如下:
\documentclass{standalone}
\usepackage{tikz}
\usepackage[linguistics]{forest}
\begin{document}
\bracketset{action character=@}
\newcount\xcount
\def\x#1{@@\advance\xcount1
\edef\xtemp{[$\noexpand\times_{\the\xcount}$[#1]]}%
\expandafter\bracketResume\xtemp
}
\begin{forest}
phantom,
delay={where level=1{content={\strut #1}}{}}
@+
[
\x{the [A[.]] }
\x{girl [O[.]] }
\x{for [U[.]] }
\x{wh- [U[.]] }
\x{om [O[.]] }
\x{the [A[.]] }
\x{man [O[.]] }
\x{bought [I[.]] }
\x{the [A[.]] }
\x{book [O[.]]}]
\end{forest}
\end{document}
这是第二个 MWE 的输出:
我认为路径应该用三个参数来标识:
- 起点——例如从“女孩”和“O”下方开始路径;
- 深度 —— 例如在‘女孩’和‘O’下方的路径中走 6;
- 箭头方向;可以是:
- 无,例如‘girl’和‘O’下面的路径;
- 右,例如沿着 'girl' 左边的 'the' 下方的路径向右走 1;
- 左,例如在“bought”和“I”下方的路径上向左走 4 个;
如果箭头方向是左或右,则在箭头旁边应该有一个额外的参数,用于表示路径的最后一个语法字符,如图所示,这可能类似于\overleftarrow{O}
从“girl”和“O”开始的路径以及\overrightarrow{A}
从“bought”和“I”开始的路径;
最后的特征是从“wh”和“U”下方开始的路径的深度 1(右侧桥)和 4(左侧桥)上的“桥”(我没有更好的名字)。
非常欢迎对任何基于 TikZ 的包提出建议。
答案1
这当然还不是一个完整的答案,只是想告诉你,我不同意你对这个软件包的怀疑。在我看来,这是一个手册写得非常好的软件包,这就是为什么我相信你可以用它实现你想要的东西。这个答案的关键要素是一个宏
\Connect{<start>}{<end>}{<level>}{<label>}
在哪里start
,end
和 level
都是整数。其用法由以下 MWE 说明。
\documentclass[border=3.14mm,standalone]{standalone}
\usepackage{mathtools}
\usepackage{tikz-dependency}
\usetikzlibrary{intersections} % not used ... YET
\newcounter{depaths}
\newcommand{\Connect}[5][]{
\stepcounter{depaths}
\draw[name path=dep connect \thedepaths](\wordref{2}{#2}) -- ++ (0,-#4) coordinate (aux-\thedepaths-1) -|
(\wordref{2}{#3}) coordinate[pos=0.5] (aux-\thedepaths-2);
\draw[-latex,shorten >=1pt] (aux-\thedepaths-1) -- (aux-\thedepaths-2);
\ifnum#3>#2
\node[anchor=south east] at (aux-\thedepaths-2) {#5};
\else
\node[anchor=south west] at (aux-\thedepaths-2) {#5};
\fi
\foreach \X in {1,...,#4}
{\fill (\wordref{2}{#2}) ++ (0,-\X) circle(1.5pt);
\fill (\wordref{2}{#3}) ++ (0,-\X) circle(1.5pt);}
\pgfmathtruncatemacro{\DeltaX}{abs(#3-#2)}
\ifnum\DeltaX>1
\foreach \X in {#2,...,#3}
\fill (\wordref{2}{\X}) ++ (0,-#4) circle(1.5pt);
\fi
}
\begin{document}
\begin{dependency}
\begin{deptext}[column sep=1em]
the \& girl \& for \& wh- \& om \& the \& man \& bought \& the \& book\\
A \& O \& U \& U \& O \& A \& O \& I \& A \& O\\
\end{deptext}
\Connect{1}{2}{1}{$\overleftarrow{O}$}
\Connect{4}{2}{6}{$\overleftarrow{O}$}
\Connect{4}{3}{1}{$\overleftarrow{O}$}
\end{dependency}
\end{document}
附录: 这是一实验版本在交叉点上绘制圆弧。如您所见,有相当多的\typeout
s,这远非完美,但也许是一个开始。更准确地说,只要满足以下条件之一,就不会绘制圆弧:
- 第一条路径的起点和终点就是第二条路径的起点和终点。
- 第一条路径的结束位置与第二条路径的开始或结束位置相同。
- 路径具有相同的级别(=宏的第三个参数
\Connect{4}{3}{1}
)。
很容易看出,如果满足任何一个条件,就很可能不会有弧,但以下两条路径也不会有弧:
******************
| | |
*---*-*
| |
*-*
虽然很麻烦,但也可以弥补这个漏洞。这取决于这是否会真的也习惯于某个地方,我可能会获得足够的动力来做到这一点,也使宏更加Ti钾Zy,即与 pgfkeys 一起工作。
\documentclass[border=3.14mm,standalone]{standalone}
\usepackage{mathtools}
\usepackage{tikz-dependency}
\usetikzlibrary{intersections}
\newcounter{depaths}
\newif\ifIntersect
\tikzset{every picture/.append style={execute at begin picture={%
\xdef\LstPaths{}% may be unnecessary
\setcounter{depaths}{0}}}}
\newcommand{\Connect}[5][]{
\stepcounter{depaths}%\typeout{new\space path\space\thedepaths}
\draw[name path=dep connect \thedepaths-tmp](\wordref{2}{#2}) -- ++ (0,-#4) coordinate (aux-\thedepaths-1) -|
(\wordref{2}{#3}) coordinate[pos=0.5] (aux-\thedepaths-2);
\draw[-latex,shorten >=1pt] (aux-\thedepaths-1) -- (aux-\thedepaths-2);
\ifnum#3>#2
\node[anchor=south east] at (aux-\thedepaths-2) {#5};
\else
\node[anchor=south west] at (aux-\thedepaths-2) {#5};
\fi
\foreach \X in {1,...,#4}
{\fill (\wordref{2}{#2}) ++ (0,-\X) circle(1.5pt);
\fill (\wordref{2}{#3}) ++ (0,-\X) circle(1.5pt);}
\pgfmathtruncatemacro{\DeltaX}{abs(#3-#2)}
\ifnum\DeltaX>1
\foreach \X in {#2,...,#3}
\fill (\wordref{2}{\X}) ++ (0,-#4) circle(1.5pt);
\fi
\ifnum\thedepaths>1
\foreach \Y [count=\X] in \LstPaths
{\Intersectfalse
%\typeout{checking\space intersection\space with\space path\space \X}
\path[name intersections={of=dep connect \thedepaths-tmp and dep
connect \X-tmp,total=\t}] \pgfextra{%\typeout{\t:\Y}
\ifnum\t>0
\global\Intersecttrue
%\typeout{paths\space\X\space and\space\thedepaths \space\space have\space common\space points}
\fi};
\foreach \V [count=\W] in \Y
{\ifcase\W % no 0
\or % 1 boring
\or % 2
\ifnum\V=#2
%\typeout{case2-2}
\global\Intersectfalse
\fi
\ifnum\V=#3
%\typeout{case2-3}
\global\Intersectfalse
\fi
\or
\ifnum\V=#3
%\typeout{case3-3}
\global\Intersectfalse
\fi
\ifnum\V=#2
%\typeout{case3-2}
\global\Intersectfalse
\fi
\or
\ifnum\V=#4
%\typeout{case4}
\global\Intersectfalse
\fi
\fi}
\ifIntersect
\node[circle,fill=white,outer sep=0pt,minimum size=10pt] (aux-int) at (intersection-1){};
\draw (aux-int.south) -- (aux-int.north);
\draw[white,double=black] (aux-int.west) to[out=60,in=120] (aux-int.east);
%\typeout{real\space intersection\space of\space path\space \thedepaths\space with\space path\space \X}
\fi
}
\fi
\ifnum\thedepaths=1
\xdef\LstPaths{{\thedepaths,#2,#3,#4}}
\else
\xdef\LstPaths{\LstPaths,{\thedepaths,#2,#3,#4}}
\fi
}
\begin{document}
\begin{dependency}
\begin{deptext}[column sep=1em]
the \& marmot \& for \& wh- \& om \& the \& duck \& bought \& the \& cake\\
A \& O \& U \& U \& O \& A \& O \& I \& A \& O\\
\end{deptext}
\Connect{1}{2}{1}{$\overleftarrow{O}$}
\Connect{4}{2}{6}{$\overleftarrow{O}$}
\Connect{3}{8}{4}{$\overleftarrow{3}$}
\Connect{5}{3}{1}{$\overleftarrow{O}$}
\end{dependency}
\end{document}