有没有办法构造一棵树,其子节点位于指定位置,以便TikZ
根据和计算树中其他节点的level distance
位置sibling distance
?
我之所以问这个问题,是因为最终我有一个,matrix of nodes
并且想从右侧将一棵树长入第二列的向量中。到目前为止,我所拥有的一个最小工作示例是:
\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{positioning,matrix}
\begin{document}
\tikzset{
img/.initial={},
img/.value required,
%
image placeholder/.style={%
execute at end node=\phantom{\pgfuseimage{\pgfkeysvalueof{/tikz/img}}}}
}
\pgfdeclareimage[height=7em]{ballot}{fptp-ballot}
\begin{tikzpicture}[every node/.style={draw=black},
every matrix/.style={ampersand replacement=\&}]
\matrix (ballot counts)
[matrix of nodes, nodes in empty cells, cells={right},
column 1/.append style={%
nodes={scale=0.5}, image placeholder, img=ballot}]
{
\& Alice: $0$ \\
\& Bob: $0$ \\
\& Charlie: $0$ \\
\& Dave: $0$ \\
};
\matrix (ballot box)
[node distance=2 and 2, right=of ballot counts,
matrix of nodes, nodes in empty cells,
cells={image placeholder, img=ballot}]
{
\& \\
\& \\
};
\matrix (max tree)
[matrix anchor=west]
at (ballot counts.east)
{
\node {root} [grow=left, level/.style={sibling distance=7em/#1}]
child {node {left}
child {node {}}
child {node {}}}
child {node {right}
child {node {}}
child {node {}}}; \\
};
\end{tikzpicture}
\end{document}
我想修改此图,以便叶子max tree
附加到第二列的四个条目ballot counts
(即 Alice:0,...)。
在此问题的早期版本中,@TomBombadil 建议我可以使用at
来明确定位树的叶子。 问题是,内部节点也必须明确定位。 我希望有某种方式来利用level distance
和sibling distance
。
编辑:根据 @percusse 的评论“生长树并将节点放在每个兄弟节点的左边”可能是一个答案,我想出了以下 MWE,它或多或少地满足了我的要求。(@percusse:这是你想要的,还是你在想其他事情?)
\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{calc,positioning,matrix,fit}
\begin{document}
\tikzset{
img/.initial={},
img/.value required,
%
image placeholder/.style={%
execute at end node=\phantom{\pgfuseimage{\pgfkeysvalueof{/tikz/img}}}}
}
\pgfdeclareimage[height=7em]{ballot}{fptp-ballot}
\tikzstyle{ballot count} = [matrix of nodes, nodes in empty cells,
right, inner sep=0em,
cells={right, inner sep=0.3333em},
column 1/.append style={%
image placeholder, img=ballot, nodes={scale=0.5}}]
\begin{tikzpicture}[every node/.style={draw},
every matrix/.style={ampersand replacement=\&}]
% Construct a fake ballot count ``leaf'' to measure its height.
\matrix (tmp) [ballot count, overlay,
draw=none, nodes={draw=none}]
{ \\ };
% Measure the height of the fake ``leaf''.
\path let \p{childheight} = ($(tmp.north)-(tmp.south)$) in
% Use the height to set sibling distance so that
% there is no gap between the leaves of the tree.
[level/.append style={sibling distance=2*\y{childheight}/#1,
level distance=2cm*#1}]
node {root} [grow=left]
child {node {left}
child [child anchor=east] foreach \name in {Alice, Bob}
{node (\name's count) [matrix, ballot count]
{ \& \name: $0$ \\ }}}
child {node {right}
child [child anchor=east] foreach \name in {Charlie, Dave}
{node (\name's count) [matrix, ballot count]
{ \& \name: $0$ \\ }}};
% Build the bounding box that contains all leaves.
\node (ballot counts)
[inner sep=0em,
fit=(Alice's count) (Bob's count)
(Charlie's count) (Dave's count)] {};
% Position a matrix to the right of the leaves.
\matrix (ballot box)
[node distance=2 and 2, right=of ballot counts,
matrix of nodes, nodes in empty cells,
cells={image placeholder, img=ballot}]
{
\& \\
\& \\
};
\end{tikzpicture}
\end{document}
这种方法有几个缺点:
我必须创建一个名为 的假叶子
tmp
,以测量任意叶子的高度。如果我能以某种方式测量叶子的高度,然后将此高度追溯传递给sibling distance
树的 ,那就更好了。由于叶子节点不再位于矩阵内,我必须明确构造一个边界框,以便将
ballot box
其定位在我想要的位置。此外,叶子节点的代码现在分布在两个子树之间;这使得树边和非叶子节点的描述变得复杂,并且需要将部分代码复制到子树之间。
我想,总的来说,代码并不像我希望的那样干净;我仍然希望有一个更干净的解决方案。但也许我只需要学会不那么贪婪。 :)
答案1
您可以命名节点,然后使用这些名称进行相对定位。您还可以使用绝对定位并执行通常对节点执行的所有操作。在示例中,自动定位的节点为红色,相对定位的节点为蓝色:
\documentclass[parskip]{scrartcl}
\usepackage[margin=15mm]{geometry}
\usepackage{tikz}
\usetikzlibrary{trees,fit,shapes,calc}
\begin{document}
\begin{tikzpicture}
\tikzstyle{level 1}=[sibling distance=40mm]
\tikzstyle{level 2}=[sibling distance=20mm]
\tikzstyle{level 3}=[sibling distance=10mm]
\node (S) {S}
child{node {N} child{node (M1) {mary}} }
child{node {VP}
child{node[fill=red,circle,text=green] (V) {V} child{node{brought }}}
child{node[fill=blue,text=yellow,circle] (NP2) at ($(V)+(2,-2)$) {NP} child{node{D} child{node (A2){a}}} child{node{N} child{node (C2) {cat}}} }
child{node[fill=blue,text=yellow,circle] (PP) at ($(NP2)+(4,1)$) {PP} child{node{IN} child{node{to}}} child{node{N} child{node{school}}} } }
;
\end{tikzpicture}
\end{document}
答案2
这是一个 Forest 版本(显然已经很晚了),但我可能没有理解这个问题,因为我的解决方案看起来与 Tom Bombadil 的答案完全不同。
这只是使用了森林fit to
和fit
。
\documentclass[border=10pt]{standalone}
\usepackage{forest}
\begin{document}
\begin{forest}
box around/.style={
tikz+={
\node [draw, inner sep=2.5pt, fit to=#1] {};
},
},
box around nodes/.style={
tikz+={
\node [draw, inner sep=2.5pt, fit=#1] {};
},
},
before typesetting nodes={
for tree={
grow=180,
child anchor=parent,
draw,
s sep'=5pt,
},
},
where n children=0{
delay={
content+=: $0$,
append={[, before computing xy={l'=0pt}, anchor=east, calign with current edge, text height=10pt, text depth=10pt, text width=5pt, no edge]}
},
anchor=mid west,
tier=voters,
box around=tree,
}{},
[root
[left, box around nodes=(!1) (!rF) (!s1) (!rL)
[Alice]
[Bob]
]
[right, box around=descendants
[Charlie]
[Dave]
]
]
\node (rb) [draw, inner sep=2.5pt, fit=(!r) (!r |- !rF.north) (!r |- !rL.south), inner xsep=7.5pt] {};
\draw (!r) \foreach \i in {north,south} {edge (!r |- rb.\i)} \foreach \i in {east,west} {edge (!r -| rb.\i)} ;
\node [draw, fit=(rb), inner sep=2.5pt] {};
\node [draw, inner sep=5pt, fit=(!rF.north west) (!rL.south east) (!r21.east)] {};
\end{forest}
\end{document}