TikZ 树的子项位于指定位置?

TikZ 树的子项位于指定位置?

有没有办法构造一棵树,其子节点位于指定位置,以便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 distancesibling 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}

在此处输入图片描述

这种方法有几个缺点:

  1. 我必须创建一个名为 的假叶子tmp,以测量任意叶子的高度。如果我能以某种方式测量叶子的高度,然后将此高度追溯传递给sibling distance树的 ,那就更好了。

  2. 由于叶子节点不再位于矩阵内,我必须明确构造一个边界框,以便将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 tofit

\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}

森林版

相关内容