Tikz 树形图,带每个级别的注释

Tikz 树形图,带每个级别的注释

我在使用 tikz 绘制树时遇到了问题。

树是正确的,但“rightarrows”错误地指向与每个树级相关的文本(看起来不太好)。当然,文本也应该不带圆圈显示。

有人可以帮忙吗?

我根据这个例子编写了这棵树:http://www.texample.net/tikz/examples/merge-sort-recursion-tree

我的代码:

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{trees}

\begin{document}
\begin{tikzpicture}[level distance=1.5cm,
level 1/.style={sibling distance=3.5cm},
level 2/.style={sibling distance=1cm}]
\tikzstyle{every node}=[circle,draw]
    \node [red] {1}
        child [red] {
        node {3}
        child { node {4} }
        child [black] { node {5} }
        child [black] { node {5} }
    }
    child {
        node {3}
        child { node {4} }
        child { node {5} }
        child { node {5} }
    }
    child {
        node {3}
        child { node {4} }
        child { node {5} }
        child { node {5}
          child [grow=right] { node (q) {$\Rightarrow$} edge from parent [draw=none]
            child [grow=right] {node (q) {$\textrm{2nd level arrow indicates here}$} edge from parent[draw=none]
              child [grow=up] {node (q) {$\Rightarrow$} edge from parent[draw=none]
                child [grow=right] {node (r) {$\textrm{1st level arrow indicates here}$} edge from parent[draw=none]
                  child [grow=up] {node (s) {$\Rightarrow$} edge from parent[draw=none]            
                    child [grow=right] {node (r) {$\textrm{1st level arrow indicates here}$} edge from parent[draw=none]
                    }
                  }
                }
              }
            }
          }
        } 
      };

\end{tikzpicture}
\end{document}

答案1

您可以利用 TikZ 树节点的一个有趣功能。如果您为根节点命名,例如 ,Root则树中的所有节点也会自动命名。节点的每个子节点都Root命名为Root-1、等等。这些子节点中的每一个都可以依次有子节点,这些子节点使用相同的模式命名。例如,在您的树中,最左边的子节点将被称为,而树的最右边的节点为。Root-2Root-3Root-1-1Root-3-3

一旦知道了这些节点的名称,就可以在相对于它们的坐标处绘制任何内容。例如:

\path (Root)  ++(3cm,0) node{Foo};

将文本放置Foo3cm节点处Root

如果希望注释垂直对齐,它们应该共享水平坐标。每个注释的位置的一个很好的参考点是其y部分与注释级别相同,而x部分与最右侧节点相同的坐标。这些坐标可以使用-|语法指定。例如,坐标是一条水平线通过和 一条垂直线通过 的(Root -| Root-3-3)交点。这是下图中用红色标记的点:RootRoot-3-3

协调

以相同的方式(Root-1 -| Root-3-3)将给出位于相同水平坐标、但位于第二级和(Root-1-1 -| Root-3-3)第三级的点。

这些坐标可用于定位注释和箭头,如下面的 MWE 所示:

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{trees}

\begin{document}
\begin{tikzpicture}[level distance=1.5cm,
level 1/.style={sibling distance=3.5cm},
level 2/.style={sibling distance=1cm}]
\tikzstyle{every node}=[circle,draw]
    \node (Root) [red] {1}
        child [red] {
        node {3}
        child { node {4} }
        child [black] { node {5} }
        child [black] { node {5} }
    }
    child {
        node {3}
        child { node {4} }
        child { node {5} }
        child { node {5} }
    }
    child {
        node {3}
        child { node {4} }
        child { node {5} }
        child { node {5} }
        };
   % Comments to each level
   \begin{scope}[every node/.style={right}]
     \path (Root    -| Root-3-3) ++(5mm,0) node {$\Rightarrow$} ++(5mm,0) node {1st level arrow indicates here};
     \path (Root-1  -| Root-3-3) ++(5mm,0) node {$\Rightarrow$} ++(5mm,0) node {2nd level arrow indicates here};
     \path (Root-1-1-| Root-3-3) ++(5mm,0) node {$\Rightarrow$} ++(5mm,0) node {3rd level arrow indicates here};
   \end{scope}

\end{tikzpicture}
\end{document}

其结果是:

最终输出

当然,这种重复性任务最好用循环来处理。在这种情况下,我将使用一个名为的变量\text来循环遍历每个级别的注释,并让循环体计算适当的坐标。我使用了一个卑鄙的技巧,在循环的每次迭代中,将字符串“-1”添加到宏的末尾\level,这样第一次迭代就会扩展为Root,第二次扩展为Root-1,第三次扩展为,Root-1-1依此类推:

 \begin{scope}[every node/.style={right}]
   \xdef\level{Root}  % Initial top level
   \def\rightmostnode{Root-3-3}   % Name of the node with greater x coordinate
   \foreach \text in {1st level arrow indicates here,
                      2nd level arrow indicates here,
                      3rd level arrow indicates here}
   {
      \path (\level -|\rightmostnode) ++(5mm,0) node{$\Rightarrow$} ++(5mm,0) node {\text};
      \xdef\level{\level-1}
   }
 \end{scope}

请注意,这个“通用”解决方案会产生相同的结果,但比最初的更直接的解决方案更复杂,占用更多行和内存。但我忍不住要展示它。这是程序员的通病。

答案2

您可以使用本问题中描述的技术如何绘制附加到 tikz-qtree 的自定义节点?使用 TikZ 的范围机制将注释绘制为第一棵树旁边的单独树。这样您就可以正确排列级别。对于大多数树,tikz-qtree包提供了用于输入树本身的更简单的语法。

\documentclass{article}
\usepackage{tikz}
\usepackage{tikz-qtree}
\begin{document}

\begin{tikzpicture}[every tree node/.style={draw,circle},edge from parent path={(\tikzparentnode) -- (\tikzchildnode)},sibling distance=.5cm]
\Tree [.\node[red] (1) {1};
        \edge[red]; [.\node[red] (3) {3}; \edge[red];[.\node[red] (4) {4}; ] [.5 ] [.5 ] ] 
        [.3 [.4 ] [.5 ] [.5 ] ]
        [.3 [.4 ] [.5 ] [.5 ] ]
      ]
\begin{scope}[xshift=3in,every tree node/.style={},edge from parent path={}]
\Tree [.{First level} [.{Second Level} [.{Third level} ]]]
\end{scope}
\end{tikzpicture}
\end{document}

代码输出

答案3

这是一个 Forest 解决方案。

\documentclass[tikz, border=5pt]{standalone}
\usepackage{forest}

\begin{document}
\begin{forest}
  for tree={
    circle,
    draw,
  },
  arrow just/.style={
    tikz+={
      \node [anchor=mid west] at (.mid -| e) {$\Rightarrow$ #1};
    },
  },
  colour me/.style={
    draw=#1,
    edge={draw=#1},
    text=#1,
  },
  trail/.style={
    colour me=#1,
    for ancestors={colour me=#1},
  },
  tikz+={\coordinate (e) at (current bounding box.east);}
  [1, arrow just={1st level arrow indicates here}
    [3, arrow just={2nd level arrow indicates here}
      [4, arrow just={3rd level arrow indicates here}, trail=red]
      [5]
      [5]
    ]
    [3
      [4]
      [5]
      [5]
    ]
    [3
      [4]
      [5]
      [5]
    ]
  ]
\end{forest}
\end{document}

森林解决方案

答案4

另一种解决方案是使用istgame包裹:

在此处输入图片描述

\documentclass{standalone}

\usepackage{amsmath}
\usepackage{istgame}

\begin{document}

\begin{istgame}
% tree
\setistOvalNodeStyle{6mm}
\xtdistance{15mm}{35mm}
\istrooto(0)[draw=red,red]{1}
  \istb[red]
  \istb
  \istb
  \endist
\xtdistance{15mm}{10mm}
\istrooto(1)(0-1)[draw=red,red]{3} 
  \istb[red]{}{4}[center,circle,draw,fill=white,red]
  \xtShowEndPoints[oval node]
  \istb{}{5}[center]
  \istb{}{5}[center]
  \endist
\istrooto(2)(0-2){3} 
  \istb{}{4}[center] 
  \istb{}{5}[center]
  \istb{}{5}[center]
  \endist
\istrooto(3)(0-3){3} 
  \istb{}{4}[center] 
  \istb{}{5}[center]
  \istb{}{5}[center]
  \endist
% level comments
\coordinate (z) at (3-3);
\coordinate (w) at ([xshift=1cm]z);
\node at (0-|w) [right] {$\Rightarrow$ 1st level arrow indicates here};
\node at (1-|w) [right] {$\Rightarrow$ 2nd level arrow indicates here};
\node at (z-|w) [right] {$\Rightarrow$ 3rd level arrow indicates here};
\end{istgame}

\end{document}

(添加)

或者,您可以用以下代码替换最后一部分(来自 istgame 版本 2.0):

% level comments
\xtTimeLineH[draw=none](0){0}{5.5}{$\Rightarrow$ 1st level arrow indicates here}
\xtTimeLineH[draw=none](1){0}{5.5}{$\Rightarrow$ 2nd level arrow indicates here}
\xtTimeLineH[draw=none](3-3){0}{5.5}{$\Rightarrow$ 3rd level arrow indicates here}

相关内容