另一个带有森林的层次图

另一个带有森林的层次图

我正在尝试适应这种以森林为基础的层次图构建我自己的分类法。这是第一次尝试

\documentclass[border=1pt]{standalone}

\usepackage{forest}
\usetikzlibrary{arrows.meta, shapes.geometric, calc, shadows}

\colorlet{mygreen}{green!75!black}
\colorlet{col1in}{red!30}
\colorlet{col1out}{red!40}
\colorlet{col2in}{mygreen!40}
\colorlet{col2out}{mygreen!50}
\colorlet{col3in}{blue!30}
\colorlet{col3out}{blue!40}
\colorlet{col4in}{mygreen!20}
\colorlet{col4out}{mygreen!30}
\colorlet{col5in}{blue!10}
\colorlet{col5out}{blue!20}
\colorlet{col6in}{blue!20}
\colorlet{col6out}{blue!30}
\colorlet{col7out}{orange}
\colorlet{col7in}{orange!50}
\colorlet{col8out}{orange!40}
\colorlet{col8in}{orange!20}
\colorlet{linecol}{blue!60}

\begin{document}

\colorlet{mygreen}{green!75!black}
\colorlet{col1in}{red!30}
\colorlet{col1out}{red!40}
\colorlet{col2in}{mygreen!40}
\colorlet{col2out}{mygreen!50}
\colorlet{col3in}{blue!30}
\colorlet{col3out}{blue!40}
\colorlet{col4in}{mygreen!20}
\colorlet{col4out}{mygreen!30}
\colorlet{col5in}{blue!10}
\colorlet{col5out}{blue!20}
\colorlet{col6in}{blue!20}
\colorlet{col6out}{blue!30}
\colorlet{col7out}{orange}
\colorlet{col7in}{orange!50}
\colorlet{col8out}{orange!40}
\colorlet{col8in}{orange!20}
\colorlet{linecol}{blue!60}

\pgfkeys{/forest,
  rect/.append style={rectangle, rounded corners=2pt, inner color=col6in, outer color=col6out},
  ellip/.append style={ellipse, inner color=col5in, outer color=col5out},
  orect/.append style={rect, font=\sffamily\bfseries\LARGE, text width=325pt, text centered, minimum height=10pt, outer color=col7out, inner color=col7in},
  oellip/.append style={ellip, inner color=col8in, outer color=col8out, font=\sffamily\bfseries\large, text centered},
}
\begin{forest}
  for tree={
      font=\sffamily\bfseries,
      line width=1pt,
      draw=linecol,
      ellip,
      align=center,
      child anchor=north,
      parent anchor=south,
      drop shadow,
      l sep+=12.5pt,
      edge path={
        \noexpand\path[color=linecol, rounded corners=5pt, >={Stealth[length=10pt]}, line width=1pt, ->, \forestoption{edge}]
          (!u.parent anchor) -- +(0,-5pt) -|
          (.child anchor)\forestoption{edge label};
        },
      where level={3}{tier=tier3}{},
      where level={0}{l sep-=15pt}{},
      where level={1}{
        if n={1}{
          edge path={
            \noexpand\path[color=linecol, rounded corners=5pt, >={Stealth[length=10pt]}, line width=1pt, ->, \forestoption{edge}]
              (!u.west) -| (.child anchor)\forestoption{edge label};
            },
        }{
          edge path={
            \noexpand\path[color=linecol, rounded corners=5pt, >={Stealth[length=10pt]}, line width=1pt, ->, \forestoption{edge}]
              (!u.east) -| (.child anchor)\forestoption{edge label};
            },
        }
      }{},
  }
  [Break Causes, inner color=col1in, outer color=col1out
    [Locators, inner color=col2in, outer color=col2out
      [Structure-Based\\Locators, inner color=col4in, outer color=col4out
        [Hierarchy-based locator\\Target Not Found]
        [, phantom, calign with current]
        [Hierarchy-based locator\\Target Not Found]
      ]
      [Attribute-based\\Locators, inner color=col4in, outer color=col4out
        [Element Text\\Not Found]
        [, phantom, calign with current]
        [Element\\Attribute\\Not Found
          [Id attribute\\Not Found]
          [Href attribute\\Not Found]
          [Alt attribute\\Not Found]
          [Name attribute\\Not Found]
          [Type attribute\\Not Found]
          [Value attribute\\Not Found]
          [Class attribute\\Not Found]
          [Click attribute\\Not Found]
        ]
      ]
    ]
    [Values/Actions, inner color=col3in, outer color=col3out
      [Invalid Text Field\\Value Input]
      [Missing Value]
      [Value Deleted\\from Dropdown List]
      [, phantom, calign with current]
      [Unexpected\\Assertion Value]
      [Exceeding Action]
      [Modified Statement]
    ]
    [Page Reloading, inner color=col3in, outer color=col3out
      [Page Reload\\Needed]
      [, phantom, calign with current]
      [Page Reload\\no longer\\Needed]
    ]
    [JavaScript Popup\\Boxes, inner color=col3in, outer color=col3out
      [User Session\\Made Longer]
      [, phantom, calign with current]
      [User Session\\Made Shorter]
    ]
  ]
%  \begin{scope}[color = linecol, rounded corners = 5pt,
%    >={Stealth[length=10pt]}, line width=1pt, ->]
%    %\draw (sse2.south) -- (us.north -| sse2.south);
%    %\draw (sse3.south) -- (us.north -| sse3.south);
%    %\coordinate (c1) at ($(sse1.south)!2/5!(sse2.south)$);
%    %\coordinate (c2) at ($(sse3.south)!2/5!(sse4.south)$);
%    %\draw (sse1.south) -- +(0,-10pt) -| (us.north -| c1);
%    %\draw (sse4.south) -- +(0,-10pt) -| (us.north -| c2);
%  \end{scope}
\end{forest}
\end{document}

输出结果如下: 在此处输入图片描述

但是,由于存在许多叶子,布局非常小且难以阅读。因此,我尝试使用

grow' = east,
child anchor=west,
parent anchor=east,

产生更好的结果:

在此处输入图片描述

我想进一步增强它:1)更好、更干净的边缘布局,2)每个边缘都有两个标签:一个在上面,另一个在下面

对我的 MWE 有什么提示吗?也许森林太复杂,无法构建这种图表?

答案1

要使箭头正确,您必须手动旋转它们。现在它们首先向下 5pt,然后-|到子节点。将其更改为向右 5pt,然后是|-。第二个问题是椭圆的宽度非常不均匀。所以我将它们设置为minimum width=60mm以便更好地对齐它们。

\documentclass[border=1pt]{standalone}

\usepackage{forest}
\usetikzlibrary{arrows.meta, shapes.geometric, calc, shadows}

\colorlet{mygreen}{green!75!black}
\colorlet{col1in}{red!30}
\colorlet{col1out}{red!40}
\colorlet{col2in}{mygreen!40}
\colorlet{col2out}{mygreen!50}
\colorlet{col3in}{blue!30}
\colorlet{col3out}{blue!40}
\colorlet{col4in}{mygreen!20}
\colorlet{col4out}{mygreen!30}
\colorlet{col5in}{blue!10}
\colorlet{col5out}{blue!20}
\colorlet{col6in}{blue!20}
\colorlet{col6out}{blue!30}
\colorlet{col7out}{orange}
\colorlet{col7in}{orange!50}
\colorlet{col8out}{orange!40}
\colorlet{col8in}{orange!20}
\colorlet{linecol}{blue!60}

\begin{document}

\colorlet{mygreen}{green!75!black}
\colorlet{col1in}{red!30}
\colorlet{col1out}{red!40}
\colorlet{col2in}{mygreen!40}
\colorlet{col2out}{mygreen!50}
\colorlet{col3in}{blue!30}
\colorlet{col3out}{blue!40}
\colorlet{col4in}{mygreen!20}
\colorlet{col4out}{mygreen!30}
\colorlet{col5in}{blue!10}
\colorlet{col5out}{blue!20}
\colorlet{col6in}{blue!20}
\colorlet{col6out}{blue!30}
\colorlet{col7out}{orange}
\colorlet{col7in}{orange!50}
\colorlet{col8out}{orange!40}
\colorlet{col8in}{orange!20}
\colorlet{linecol}{blue!60}

\pgfkeys{/forest,
  rect/.append style={rectangle, rounded corners=2pt, inner color=col6in, outer color=col6out},
  ellip/.append style={ellipse, inner color=col5in, outer color=col5out ,minimum width=60mm},
  orect/.append style={rect, font=\sffamily\bfseries\LARGE, text width=325pt, text centered, minimum height=10pt, outer color=col7out, inner color=col7in},
  oellip/.append style={ellip, inner color=col8in, outer color=col8out, font=\sffamily\bfseries\large, text centered},
}
\begin{forest}
  for tree={
    grow' = east,
    child anchor=west,
    parent anchor=east,
    font=\sffamily\bfseries,
      line width=1pt,
      draw=linecol,
      ellip,
      align=center,
      %child anchor=north,
      %parent anchor=south,
      drop shadow,
      l sep+=12.5pt,
      edge path={
        \noexpand\path[color=linecol, rounded corners=5pt, >={Stealth[length=10pt]}, line width=1pt, ->, \forestoption{edge}]
          (!u.parent anchor) -- +(5pt,0) |-
          (.child anchor)\forestoption{edge label};
        },
      where level={3}{tier=tier3}{},
      %where level={0}{l sep-=15pt}{},
      where level={1}{
        if n={1}{
          edge path={
            \noexpand\path[color=linecol, rounded corners=5pt, >={Stealth[length=10pt]}, line width=1pt, ->, \forestoption{edge}]
              (!u.east) -- +(5pt,0pt) |- (.child anchor)\forestoption{edge label};
            },
        }{
          edge path={
            \noexpand\path[color=linecol, rounded corners=5pt, >={Stealth[length=10pt]}, line width=1pt, ->, \forestoption{edge}]
              (!u.east)  -- +(5pt,0pt) |- (.child anchor)\forestoption{edge label};
            },
        }
      }{},
  }
  [Break Causes, inner color=col1in, outer color=col1out
    [Locators, inner color=col2in, outer color=col2out
      [Structure-Based\\Locators, inner color=col4in, outer color=col4out
        [Hierarchy-based locator\\Target Not Found]
        [, phantom, calign with current]
        [Hierarchy-based locator\\Target Not Found]
      ]
      [Attribute-based\\Locators, inner color=col4in, outer color=col4out
        [Element Text\\Not Found]
        [, phantom, calign with current]
        [Element Attribute\\Not Found
          [Id attribute\\Not Found]
          [Href attribute\\Not Found]
          [Alt attribute\\Not Found]
          [Name attribute\\Not Found]
          [Type attribute\\Not Found]
          [Value attribute\\Not Found]
          [Class attribute\\Not Found]
          [Click attribute\\Not Found]
        ]
      ]
    ]
    [Values/Actions, inner color=col3in, outer color=col3out
      [Invalid Text Field\\Value Input]
      [Missing Value]
      [Value Deleted\\from Dropdown List]
      [, phantom, calign with current]
      [Unexpected\\Assertion Value]
      [Exceeding Action]
      [Modified Statement]
    ]
    [Page Reloading, inner color=col3in, outer color=col3out
      [Page Reload\\Needed]
      [, phantom, calign with current]
      [Page Reload\\no longer\\Needed]
    ]
    [JavaScript Popup\\Boxes, inner color=col3in, outer color=col3out
      [User Session\\Made Longer]
      [, phantom, calign with current]
      [User Session\\Made Shorter]
    ]
  ]
%  \begin{scope}[color = linecol, rounded corners = 5pt,
%    >={Stealth[length=10pt]}, line width=1pt, ->]
%    %\draw (sse2.south) -- (us.north -| sse2.south);
%    %\draw (sse3.south) -- (us.north -| sse3.south);
%    %\coordinate (c1) at ($(sse1.south)!2/5!(sse2.south)$);
%    %\coordinate (c2) at ($(sse3.south)!2/5!(sse4.south)$);
%    %\draw (sse1.south) -- +(0,-10pt) -| (us.north -| c1);
%    %\draw (sse4.south) -- +(0,-10pt) -| (us.north -| c2);
%  \end{scope}
\end{forest}
\end{document}

在此处输入图片描述

我还没有研究如何标记边缘。要做到这一点,你可能需要稍微缩小示例。

答案2

当前版本的 Forest 使这种类型的树变得容易得多。我建议充分利用它。

椭圆形在这里不是一个好选择。要么使用矩形,或许使用rounded corners,要么使用rounded rectangle。否则,这种形状只会占用空间,而且会使树看起来有点奇怪。

\tikzset{%
  ellip/.append style={rounded rectangle, ...},
}

[ellip当然,现在名字叫错了,但是 TeX 不会在意。]

Forest 现在有一个edges提供 的库forked edges。这意味着我们不必担心树的生长方向:树枝方向的变化会自动适应。

  forked edges,

这些phantom节点除了在错误的地方增加难看的垂直间距外,没有做太多事情。我会摆脱它们。但是,如果您希望恢复它们,我已经添加了一些代码来自动添加它们。如果父级有奇数个子级,我们会与中间子级对齐。否则,不对齐。(这棵树中没有奇数个子级,但如果您在某处添加或减去一个,可能会有。)

  where={isodd(n_children())}{%
    for n/.wrap pgfmath arg={{#1}{calign with current edge}}{int((n_children()+1)/2)}
  }{% if you really want the phantoms in when there is an even number of children, uncomment this
%     if n children=0{}{%
%       delay={%
%         for n/.wrap pgfmath arg={{#1}{%
%             insert after={[, phantom, calign with current edge]},
%           }}{int((n_children())/2)},
%       }
%     },
  },

不过,我会phantom在根节点的子节点中使用 以避免边缘看起来很奇怪。或者,删除rounded corners。(但我非常喜欢它们,所以我添加了幻影。)

    ]
    [, phantom, calign with current edge]
    [Values/Actions, ellip=3

如果没有一点帮助,Forest 无法正确放置节点。我l sep稍微增加了一点,设置anchor=parent并对齐了第 2 级中的所有节点来处理这个问题。

    for tree={%
      ...
      anchor=parent,
      l sep'+=5pt,
      ...
    },
    ...
    where level=2{tier=second}{},

l sep请注意,如果您不使用边缘箭头,则无需增加。我不知道您是否真的需要这些。我可能会放弃它们,但在这里我只是将它们设置为正常大小而不是超大。

我删除了未使用的样式和颜色以及重复的定义,并简化了着色处理方式,以便树的规范更加清晰。

\tikzset{%
  ellip/.append style={rounded rectangle, inner color=col#1in, outer color=col#1out},
}

允许我们分别用和来写ellip=5内着色和外着色。col5incol5out

初步结果如下:

初步结果

初始代码:

\documentclass[tikz,border=10pt]{standalone}
\usepackage[edges]{forest}
\usetikzlibrary{arrows.meta,shapes.geometric,shadows}
\begin{document}

\colorlet{mygreen}{green!75!black}
\colorlet{col1in}{red!30}
\colorlet{col1out}{red!40}
\colorlet{col2in}{mygreen!40}
\colorlet{col2out}{mygreen!50}
\colorlet{col3in}{blue!30}
\colorlet{col3out}{blue!40}
\colorlet{col4in}{mygreen!20}
\colorlet{col4out}{mygreen!30}
\colorlet{col5in}{blue!10}
\colorlet{col5out}{blue!20}
\colorlet{linecol}{blue!60}

\tikzset{%
  ellip/.append style={rounded rectangle, inner color=col#1in, outer color=col#1out},
}
\begin{forest}
  forked edges,
  for tree={
      font=\sffamily\bfseries,
      line width=1pt,
      draw=linecol,
      ellip=5,
      align=center,
      grow'=0,
      edge+={color=linecol, line width=1pt, rounded corners=5pt, -Stealth},
      drop shadow,
      anchor=parent,
      l sep'+=5pt,
  },
  where={isodd(n_children())}{%
    for n/.wrap pgfmath arg={{#1}{calign with current edge}}{int((n_children()+1)/2)}
  }{% if you really want the phantoms in when there is an even number of children, uncomment this
%     if n children=0{}{%
%       delay={%
%         for n/.wrap pgfmath arg={{#1}{%
%             insert after={[, phantom, calign with current edge]},
%           }}{int((n_children())/2)},
%       }
%     },
  },
  where level=2{tier=second}{},
  [Break Causes, ellip=1
    [Locators, ellip=2
      [Structure-Based\\Locators, ellip=4
        [Hierarchy-based locator\\Target Not Found]
        [Hierarchy-based locator\\Target Not Found]
      ]
      [Attribute-based\\Locators, ellip=4
        [Element\\Text\\Not Found]
        [Element\\Attribute\\Not Found
          [Id attribute\\Not Found]
          [Href attribute\\Not Found]
          [Alt attribute\\Not Found]
          [Name attribute\\Not Found]
          [Type attribute\\Not Found]
          [Value attribute\\Not Found]
          [Class attribute\\Not Found]
          [Click attribute\\Not Found]
        ]
      ]
    ]
    [, phantom, calign with current edge]
    [Values/Actions, ellip=3
      [Invalid Text Field\\Value Input]
      [Missing Value]
      [Value Deleted\\from Dropdown List]
      [Unexpected\\Assertion Value]
      [Exceeding Action]
      [Modified Statement]
    ]
    [Page Reloading, ellip=3
      [Page Reload\\Needed]
      [Page Reload\\no longer\\Needed]
    ]
    [JavaScript Popup\\Boxes, ellip=3
      [User Session\\Made Longer]
      [User Session\\Made Shorter]
    ]
  ]
\end{forest}
\end{document}

如果您需要在边缘上贴标签,我假设您希望它们位于水平部分。如果是这样,我肯定会放弃箭头,除非您可以使它们更长。

我会通过尽量减少输入来实现这一点。我会进行设置,以便我可以将标签放入节点本身,并让 Forest 在格式化树时拆分内容。我猜你可能希望将百分比设置为 2dp,所以我用它作为示例。

我们添加一些样式来开始。

\tikzset{%
  ...
  label look/.style={font=\scriptsize},

标签的样式。现在是数字格式。

  /pgf/number format/.cd,
  fixed,
  fixed zerofill,
  precision=2,
}

我们想要几个 Forest 选项来保存标签。

\forestset{%
  declare toks={alabel}{0},
  declare toks={blabel}{0},
}

现在我们添加代码来拆分和格式化标签。

  before typesetting nodes={%
    for tree={%
      split option={content}{:}{content,alabel,blabel},
      edge label/.wrap 2 pgfmath args={node [above, label look, anchor=south east] {\pgfmathprintnumber{#1}\%} node [below, label look, anchor=north east] {\pgfmathprintnumber{#2}\%}}{alabel()}{blabel()}
    },
  },

这需要增加l sep一点以腾出空间,我增加了s sep'+=10ptLocators避免节点相互重叠。我认为 Forest 有点迷失方向。(它不会尝试跟踪标签,但会跟踪节点。)

然后我们可以这样写,

 Structure-Based\\Locators:9:4.658

对于具有 的节点,其9.00%上方和下方都有标签4.66%,并且内容为Structure-Based\\Locators

结果如下:

標籤樹

完整代码:

\documentclass[tikz,border=10pt]{standalone}
\usepackage[edges]{forest}
\usetikzlibrary{arrows.meta,shapes.geometric,shadows}
\begin{document}

\colorlet{mygreen}{green!75!black}
\colorlet{col1in}{red!30}
\colorlet{col1out}{red!40}
\colorlet{col2in}{mygreen!40}
\colorlet{col2out}{mygreen!50}
\colorlet{col3in}{blue!30}
\colorlet{col3out}{blue!40}
\colorlet{col4in}{mygreen!20}
\colorlet{col4out}{mygreen!30}
\colorlet{col5in}{blue!10}
\colorlet{col5out}{blue!20}
\colorlet{linecol}{blue!60}

\tikzset{%
  ellip/.append style={rounded rectangle, inner color=col#1in, outer color=col#1out},
  label look/.style={font=\scriptsize},
  /pgf/number format/.cd,
  fixed,
  fixed zerofill,
  precision=2,
}
\forestset{%
  declare toks={alabel}{0},
  declare toks={blabel}{0},
}
\begin{forest}
  forked edges,
  for tree={%
      font=\sffamily\bfseries,
      line width=1pt,
      draw=linecol,
      ellip=5,
      align=center,
      grow'=0,
      edge+={color=linecol, line width=1pt, rounded corners=5pt},
      drop shadow,
      anchor=parent,
      l sep'+=25pt,
  },
  where={isodd(n_children())}{%
    for n/.wrap pgfmath arg={{#1}{calign with current edge}}{int((n_children()+1)/2)}
  }{},
  where level=2{tier=second}{},
  before typesetting nodes={%
    for tree={%
      split option={content}{:}{content,alabel,blabel},
      edge label/.wrap 2 pgfmath args={node [above, label look, anchor=south east] {\pgfmathprintnumber{#1}\%} node [below, label look, anchor=north east] {\pgfmathprintnumber{#2}\%}}{alabel()}{blabel()}
    },
  },
  [Break Causes, ellip=1
    [Locators:5.76, ellip=2, s sep'+=10pt
      [Structure-Based\\Locators:9:4.658, ellip=4
        [Hierarchy-based locator\\Target Not Found:82.342:45]
        [Hierarchy-based locator\\Target Not Found:3:5.68]
      ]
      [Attribute-based\\Locators:98.3:4, ellip=4
        [Element\\Text\\Not Found:98.34:23.1]
        [Element\\Attribute\\Not Found:46.98:9
          [Id attribute\\Not Found:34:53.2345]
          [Href attribute\\Not Found:98:43.2335]
          [Alt attribute\\Not Found:78:9]
          [Name attribute\\Not Found:0.987:23]
          [Type attribute\\Not Found:11:70]
          [Value attribute\\Not Found:8:2]
          [Class attribute\\Not Found:1:6]
          [Click attribute\\Not Found:8:5]
        ]
      ]
    ]
    [, phantom, calign with current edge]
    [Values/Actions:29.8:76.2, ellip=3
      [Invalid Text Field\\Value Input:0.987:23]
      [Missing Value:98.3:4]
      [Value Deleted\\from Dropdown List:86:34]
      [Unexpected\\Assertion Value:11:70]
      [Exceeding Action:5.76]
      [Modified Statement:0.987:23]
    ]
    [Page Reloading:98.3:4, ellip=3
      [Page Reload\\Needed:34:53.2345]
      [Page Reload\\no longer\\Needed:96:48]
    ]
    [JavaScript Popup\\Boxes:5.87:56.9, ellip=3
      [User Session\\Made Longer:34:53.2345]
      [User Session\\Made Shorter:11:70]
    ]
  ]
\end{forest}
\end{document}

相关内容