我的问题得到了一个很酷的解决方案使用 tikz/forest 绘制复杂的依赖关系图并想重用此样式来绘制图表的精简版本,该版本应该如下所示:
我现在尝试了以下操作:
\documentclass{article}
\usepackage{forest}
\usetikzlibrary{arrows.meta,bending}
\tikzset{
connect/.style={{Stealth[bend]}-{Stealth[bend]}, draw=green, shorten <=-3pt, shorten >=-3pt}
}
\forestset{
wg/.style={
for tree={
no edge,
draw,
outer ysep=1pt,
},
copy label/.style={
for children={
if content={}{
content/.pgfmath={content("!u")},
calign with current,
edge={draw,{-Triangle[open,reversed]}},
copy label,
!u.content/.pgfmath={content},
!u.content+=',
}{
copy label,
}
}
},
delay={
copy label,
for tree={name/.pgfmath={content}},
},
for tree={content format={\strut\forestoption{content}}},
where n children={0}{
tier=word,
}{},
},
}
\tikzset{deparrow/.style={-Latex,blue}}
\begin{document}
\begin{forest}
wg
[
[small]
[children]
[were]
[playing]
[outside]
]
% \draw[deparrow] (were.north) [bend.left] to ([xshift=-10pt]children.north);
\draw[deparrow] (were) to[out=north, in=north] ([xshift=-10pt]children);
\draw[deparrow] (children) to[out=north, in=north] (small);
\draw[deparrow] (were) to[out=north, in=north] (playing);
\draw[deparrow] (playing) to[out=north, in=north] (children);
\draw[deparrow] (playing) to[out=north, in=north] (outside);
\end{forest}
\end{document}
得出的结果为:
移动节点不起作用。
对于简单的图表,下面的树可能更合适:
\begin{forest}
[were
[children
[small]
]
[playing
[outside]
]
]
\end{forest}
这与原始图中的箭头相对应(其中一个从玩耍指向孩子的箭头未被表示)。
似乎可以通过样式绘制所有箭头(除了玩耍的孩子箭头)。如果这可行,可以将单纯形情况作为复杂情况的压缩版本,并且箭头(除了一个箭头)将自动绘制。
编辑:这是我在第一个答案之后所做的事情:
答案1
您可以调整现有样式,以便示例仅通过使用phantom
根并为指定适当的锚点即可工作children
:
\documentclass[tikz,border=10pt,multi]{standalone}
\usepackage{forest}
\usetikzlibrary{arrows.meta,bending}
\tikzset{
connect/.style={{Stealth[bend]}-{Stealth[bend]}, draw=green, shorten <=-3pt, shorten >=-3pt},
deparrow/.style={-Latex,blue}
}
\forestset{
wg/.style={
for tree={
no edge,
draw,
outer ysep=1pt,
},
copy label/.style={
for children={
if content={}{
content/.pgfmath={content("!u")},
calign with current,
edge={draw,{-Triangle[open,reversed]}},
copy label,
!u.content/.pgfmath={content},
!u.content+=',
}{
copy label,
}
}
},
delay={
copy label,
for tree={name/.pgfmath={content}},
},
for tree={content format={\strut\forestoption{content}}},
where n children={0}{
tier=word,
}{},
},
}
\begin{document}
\begin{forest}
wg
[,phantom
[small]
[children]
[were]
[playing]
[outside]
]
% \draw[deparrow] (were.north) [bend.left] to ([xshift=-10pt]children.north);
\draw[deparrow] (were) to[out=north, in=north] ([xshift=-10pt]children.north);
\draw[deparrow] (children) to[out=north, in=north] (small);
\draw[deparrow] (were) to[out=north, in=north] (playing);
\draw[deparrow] (playing) to[out=north, in=north] (children);
\draw[deparrow] (playing) to[out=north, in=north] (outside);
\end{forest}
\end{document}
想要更接近目标的话:
\draw[deparrow] ([xshift=-5pt]were.north) to[out=north, in=north] ([xshift=5pt]children.north);
\draw[deparrow] ([xshift=-5pt]children.north) to[out=north, in=north] ([xshift=5pt]small.north);
\draw[deparrow] ([xshift=5pt]were.north) to[out=north, in=north] ([xshift=-5pt]playing.north);
\draw[deparrow] ([xshift=-3.5pt, yshift=2.5pt]playing.north) to[out=north, in=north] ([xshift=3.5pt, yshift=2.5pt]children.north);
\draw[deparrow] ([xshift=5pt]playing.north) to[out=north, in=north] ([xshift=-5pt]outside.north);
恐怕我不完全理解你的问题的第二部分。
编辑
您可以通过向样式添加以下代码来部分自动绘制箭头wg
:
hop left/.style={
tikz+={
\draw[deparrow] ([xshift=-5pt].north) to[out=north, in=north] ([xshift=5pt]!p.north);
},
},
hop right/.style={
tikz+={
\draw[deparrow] ([xshift=5pt].north) to[out=north, in=north] ([xshift=-5pt]!n.north);
},
},
然后您可以按如下方式指定树:
\begin{forest}
wg
[,phantom
[small]
[children, hop left]
[were, hop left, hop right]
[playing, hop right]
[outside]
]
\draw[deparrow] ([xshift=-3.5pt, yshift=2.5pt]playing.north) to[out=north, in=north] ([xshift=3.5pt, yshift=2.5pt]children.north);
\end{forest}
但是,如果没有某种算法来确定箭头应该朝哪个方向移动,即它们何时应该向左跳跃、何时向右跳跃、何时同时跳跃以及何时都不跳跃,您就无法做更多的事情。除非您绘制了很多这样的树,并且跳跃的模式非常统一,否则手动指定跳跃会更容易,也不容易出错。例如,在发布的树中,您需要实现类似这样的操作:
for the phantom root node:
if it has an odd number of children then
for each of its children
if the child's number is half of the parent's number of children incremented by one and divided by two, then hop both right and left
else if the child's number is less than half of the parent's number of children incremented by one and divided by two and the child is not the first child, then hop left
else if the child is not the last child, then hop right
else do nothing
else do nothing
然后,您大概还会指定如果根节点有偶数个子节点该怎么做。如果您要绘制数百棵具有相同箭头图案的树,那么这样做可能值得。否则,只说hop left
和似乎更容易hop right
。