重新阅读forest
手册后,我发现for-c-command
指令,它对所有由某个其他节点 c 命令的节点执行某些操作。例如,将它们绘制为红色。我想知道这是否可以与非常酷的解决方案结合起来沿森林节点路径绘制线条或箭头。那么:是否可以从某个节点绘制箭头到它所指挥的所有其他节点?
答案1
这看起来很丑,但它应该说明如何解决主要问题:如何轻松地将 c 命令节点的名称压缩到\draw
代码中。
\documentclass{standalone}
\usepackage[linguistics]{forest}
\begin{document}
\begin{forest}
[CP
[C,
for c-commanded/.process=Ow{name}{tikz={\draw[->](#1)--();}}
]
[TP
[T]
[VP
[DP]
[V'
[V]
[DP]
]
]
]
]
\end{forest}
\end{document}
并与业余爱好答案的解决方案相结合:
\documentclass[convert=png]{standalone}
\usepackage[linguistics]{forest}
\usetikzlibrary{hobby}
\forestset{%
walkfromto@toLCA/.nodewalk style={
save={walkfromto@anc}{load={walk last},ancestors},
walk and save={walk from first to LCA}{
fake=parent,
while={}{
if in saved nodewalk={current}{walkfromto@anc}
{break}
{
% This doesn't work:
%%%% fake={walkfromto@toLCA={#1}}
% "save" introduces an embedded nodewalk, which doesn't restore the value
% of "fake" after doing its work ... (will be) fixed in v2.1.5
% So instead of saying "current" below, whoever uses this style must
% appropriately define walkfromto@toLCA@step.
walkfromto@toLCA@step,
fake=parent
},
},
},
},
walkfromto@fromLCA/.nodewalk style={% we're at LCA now
walk and save={walk from LCA to last}{
if in saved nodewalk={current}{walk last}{% other = LCA
}{
reverse/.process=Ow{id}{
fake={load={walk last},parent},
until={>O_={id}{##1}}{current,fake=parent}
}
}
}
},
define long step={LCA}{n args=2}{
fake={group={#1}},
% In v2.1.5, replace this workaround by "fake={walkfromto@toLCA={#2}}"
walkfromto@toLCA@step/.style={fake=current}, walkfromto@toLCA={#2},
% end of workaround (do the same in all step definitions below)
current
},
define long step={walk from to}{n args=2}{
save={walk last}{group={#2}},
walk and save={walk first}{group={#1}},
walkfromto@toLCA@step/.style={current}, walkfromto@toLCA={#2},
walk and save={walk LCA}{current},
walkfromto@fromLCA,
load={walk last},
},
between nodewalk steps/.style 2 args={
for nodewalk={#1}{every step={options/.process=OOw2{!b.name}{name}{#2}}}
},
hobby curve/.style 2 args={
for nodewalk={walk from to={current}{#1}}{},
temptoksa={},
temptoksb={},
pass through/.style={
temptoksa+/.register=temptoksb,temptoksb={..},
temptoksa+/.process=Ow{name}{##1}},
for load={walk from first to LCA}{
pass through={([yshift=2.5pt]##1.north east)}},
for load={walk LCA}{
pass through={([yshift=4.5pt]##1.south)}},
for load={walk from LCA to last}{
pass through={([yshift=2.5pt]##1.north west)}},
between nodewalk steps={load=walk first,load=walk last}{
!r.tikz+/.process=Rw{temptoksa}{%
\draw[#2] (##1.north)
to [curve through={####1}]
(##2.north);
}},
}
}
\begin{document}
\begin{forest}
[CP
[C,
for c-commanded/.process=Ow{name}{hobby curve={name=#1}{red,<-}}
]
[TP
[T]
[VP
[DP]
[V'
[V]
[DP]
]
]
]
]
\end{forest}
\end{document}
现在,我们开始初步尝试调整箭头。我修改了hobby curve
样式,使shift
s 成为参数;在 hobby 的调用中,偏移是根据级别差异计算的。远非理想,但也许是个开始...
\documentclass[convert=png]{standalone}
\usepackage[linguistics]{forest}
\usetikzlibrary{hobby}
\forestset{%
walkfromto@toLCA/.nodewalk style={
save={walkfromto@anc}{load={walk last},ancestors},
walk and save={walk from first to LCA}{
fake=parent,
while={}{
if in saved nodewalk={current}{walkfromto@anc}
{break}
{
% This doesn't work:
%%%% fake={walkfromto@toLCA={#1}}
% "save" introduces an embedded nodewalk, which doesn't restore the value
% of "fake" after doing its work ... (will be) fixed in v2.1.5
% So instead of saying "current" below, whoever uses this style must
% appropriately define walkfromto@toLCA@step.
walkfromto@toLCA@step,
fake=parent
},
},
},
},
walkfromto@fromLCA/.nodewalk style={% we're at LCA now
walk and save={walk from LCA to last}{
if in saved nodewalk={current}{walk last}{% other = LCA
}{
reverse/.process=Ow{id}{
fake={load={walk last},parent},
until={>O_={id}{##1}}{current,fake=parent}
}
}
}
},
define long step={LCA}{n args=2}{
fake={group={#1}},
% In v2.1.5, replace this workaround by "fake={walkfromto@toLCA={#2}}"
walkfromto@toLCA@step/.style={fake=current}, walkfromto@toLCA={#2},
% end of workaround (do the same in all step definitions below)
current
},
define long step={walk from to}{n args=2}{
save={walk last}{group={#2}},
walk and save={walk first}{group={#1}},
walkfromto@toLCA@step/.style={current}, walkfromto@toLCA={#2},
walk and save={walk LCA}{current},
walkfromto@fromLCA,
load={walk last},
},
between nodewalk steps/.style 2 args={
for nodewalk={#1}{every step={options/.process=OOw2{!b.name}{name}{#2}}}
},
hobby curve/.style n args=4{
for nodewalk={walk from to={current}{#1}}{},
temptoksa={},
temptoksb={},
pass through/.style={
temptoksa+/.register=temptoksb,temptoksb={..},
temptoksa+/.process=Ow{name}{##1}},
for load={walk from first to LCA}{
pass through={([#3]##1.north east)}},
for load={walk LCA}{
pass through={([#4]##1.south)}},
for load={walk from LCA to last}{
pass through={([#3]##1.north west)}},
between nodewalk steps={load=walk first,load=walk last}{
!r.tikz+/.process=Rw{temptoksa}{%
\draw[#2] (##1.north)
to [curve through={####1}]
(##2.north);
}},
}
}
\begin{document}
\begin{forest}
[CP
[C,
for c-commanded/.process=OOw2{name}{level}{hobby curve/.process=
__ Ow+dw Ow+dw
{name=#1}{red,<-}
{level}{2pt*(##1-#2+1)}{shift={(##1,##1)}}
{level}{4pt*(##1-#2+1)}{shift={(##1,##1)}}
}
]
[TP
[T]
[VP
[DP]
[V'
[V]
[DP]
]
]
]
]
\end{forest}
\end{document}