森林:当子节点缺失时,父节点与孙节点之间的定制边

森林:当子节点缺失时,父节点与孙节点之间的定制边

考虑这棵树,其中节点 C1 缺失。缺失节点可能出现在树的任何层级,并且节点可能出现在缺失节点下方的一个或多个层级。

在此处输入图片描述

绘制 B1 -> D1 和 B1 -> D2 的边的语法是什么,如红色所示,以使这些边的垂直部分与节点 C2 下方的边的垂直部分对齐?键fork sep指定l父锚点和分叉之间的距离,但我不知道如何使用它。

这是 MWE:

\documentclass[12pt,crop=true,border=1cm]{standalone}
\usepackage[edges]{forest}
\begin{document}

\begin{forest}
  for tree={
    grow'=0,
    draw,
    forked edges,
    text width=10mm,
    minimum height=5mm,
    parent anchor=east,
    child anchor=west,
    text centered,
  }
    [A,tier=level1
      [B1,tier=level2,name=B1
%        [C1 would be here, but it is missing
          [D1,tier=level4,name=D1
            [E1,tier=level5]
            [E2,tier=level5]
          ]
          [D2,tier=level4,name=D2
            [E3,tier=level5]
            [E4,tier=level5]          
          ]
%        ]
      ]
      [B2,tier=level2
        [C2,tier=level3
          [D3,tier=level4
            [E5,tier=level5]
            [E6,tier=level5]          
          ]
          [D4,tier=level4
            [E7,tier=level5]
            [E8,tier=level5]          
          ]
        ]
      ]
    ]
    % Draw the edges with the fork at the desired level.
    % The fork sep key specifies the "The l-distance between the parent anchor and the fork." 
    % See Forest manual version  July 14, 2017, p81
    \draw[red,thick] (B1.parent anchor) -- +(57pt,0) |- (D1.child anchor);
    \draw[red,thick] (B1.parent anchor) -- +(57pt,0) |- (D2.child anchor);
\end{forest}


\end{document}

更新

使用 @marmot 的代码测试扩展的 MWEfork sep发现了一些不足之处

由于 处有两个节点(C1C3) ,并且缺少tier=level3第三个节点,因此边缘形状类似于文件夹结构,而不是分叉。C2

在此处输入图片描述

删除C2D5导致树不再正确表示结构。

在此处输入图片描述

虽然我预计自动化解决方案将依赖于使用密钥fork sep,但@marmot 的解决方案看起来很接近,但可能仍然缺少一些东西。

@Zarko 发布的解决方法使用正交坐标在祖父母节点和子节点之间绘制边来定义分叉的位置。这是一种稳健且通用的方法。@Zarko,请回复您的答案。

更新2

这可能是一个强大的解决方案。它使用 (a) @marmot 的fork sep代码,(b) 将缺失的节点标识为坐标而不绘制节点形状,即[,draw=none,name=C2(c) 使用\draw命令连接到node.child anchornode.parent anchor例如:\draw (C2.child anchor) -- (C2.parent anchor);

\documentclass[12pt,crop=true,border=1cm]{standalone}
\usepackage[edges]{forest}
\forestset{
  declare dimen={my fork sep}{0.5em},
  my forked edge'/.style={
    edge={rotate/.option=!parent.grow},
    edge path'={let \noexpand\p1=($(.child anchor)-(!u.parent anchor)$) in
    (!u.parent anchor) -- ++(\noexpand\x1-\forestoption{my fork sep},0) |- (.child anchor)},
  },
  my forked edge/.style={
    on invalid={fake}{!parent.parent anchor=children},
    child anchor=parent,
    my forked edge',
  },
  my forked edges/.style={for nodewalk={#1}{my forked edge}},
  my forked edges/.default=tree,
}
\begin{document}

\begin{forest}
  for tree={
    grow'=0,
    draw,
    my forked edges,my fork sep=8pt,
    text width=10mm,
    minimum height=5mm,
    parent anchor=east,
    child anchor=west,
    text centered,
  }
    [A,tier=level1
      [B1,tier=level2,name=B1
        [C1% would be here, but it is missing
          [D1,tier=level4,name=D1a
            [E1,tier=level5]
            [E2,tier=level5]
          ]
          [D2,tier=level4,name=D2a
            [E3,tier=level5]
            [E4,tier=level5]
          ]
          [D3,tier=level4,name=D3a
            [E5,tier=level5]
            [E6,tier=level5]
          ]
        ]
        [,draw=none,name=C2                           
          [D4,tier=level4,name=D1b
            [E7,tier=level5]
            [E8,tier=level5]
          ]
          [,draw=none,name=D5 
            [E9,tier=level5]
            [E10,tier=level5]
          ]                                   
        ]                                     
      ]
      [B2,tier=level2
        [C3,tier=level3
          [D6,tier=level4
            [E11,tier=level5]
            [E12,tier=level5]
          ]
          [D7,tier=level4
            [E13,tier=level5]
            [E14,tier=level5]
          ]
        ]
      ]
    ]
    \draw (C2.child anchor) -- (C2.parent anchor);
    \draw (D5.child anchor) -- (D5.parent anchor);
\end{forest}

\end{document}

在此处输入图片描述

答案1

我不知道这个问题的扩展版本是什么,因为现在的问题是一个答案而不是一个问题。

因此,我的目标是做两件事:

  • 回答非扩展问题;

  • 在扩展答案问题中重现结果。

基本上,我想提出一些更简单的东西,它不需要绘制任何东西,不需要样式的变体forked edges(尽管它确实使用了样式原始版本的包装器)并且让您将缺失的节点指定为空节点。

此外,tiers 的分配是自动化的,并且相对锚点的使用使代码更加灵活。

包装器样式的名字很无趣,my tree定义如下:

\forestset{
  my tree/.style={
    forked edges,

注意forked edges应该不是在 的范围内。要么在该范围内for tree使用,要么像这里一样,保持在范围之外。forked edgeforked edges

    for tree={
      grow'=0,
      draw,
      text width=10mm,
      minimum height=5mm,
      text centered,
      tier/.option=level,

这使级别自动化,因为级别完全决定了所需的层级。

    },
    delay={
      where content={}{content=\phantom{X},draw=none, child anchor=children}{}

如果您想忽略某个节点,请将该节点留空。然后,此代码将添加一个幻影X(以避免费力地尝试找出正确的高度 - 显然其他节点超过了最小值5mm)。该节点将具有标准分配的宽度,但不会被绘制。child anchor但是,更改 会产生使其看起来好像没有节点的效果。本质上,这会将分支从父节点一直延伸到节点的中心,如果您在远端有一个坐标,而不是常规宽度节点,就会发生这种情况。

在某些情况下,您需要一个坐标,但在这里,不走这条路更容易。如果您真的想要真正的coordinates 而不是相似的 s,我建议稍后在 中移动坐标before drawing tree

    },
  },
}

就是这样。

现在我们可以写

\begin{forest}
  my tree
    [A
      [B1
       [
          [D1
            [E1]
            [E2]
          ]
          [D2
            [E3]
            [E4]          
          ]
       ]
      ]
      [B2
        [C2
          [D3
            [E5]
            [E6]          
          ]
          [D4
            [E7]
            [E8]          
          ]
        ]
      ]
    ]
\end{forest}
\begin{forest}
  my tree,
    [A
      [B1
        [
          [D1
            [E1]
            [E2]
          ]
          [D2
            [E3]
            [E4]
          ]
          [D3
            [E5]
            [E6]
          ]
        ]
        [                        
          [D4
            [E7]
            [E8]
          ]
          [
            [E9]
            [E10]
          ]                                   
        ]                                     
      ]
      [B2
        [C3
          [D6
            [E11]
            [E12]
          ]
          [D7
            [E13]
            [E14]
          ]
        ]
      ]
    ]
\end{forest}

生产

简化代码的结果

\documentclass[12pt,border=10pt]{standalone}
\usepackage[edges]{forest}
\forestset{
  my tree/.style={
    forked edges,
    for tree={
      grow'=0,
      draw,
      text width=10mm,
      minimum height=5mm,
      text centered,
      tier/.option=level,
    },
    delay={
      where content={}{content=\phantom{X},draw=none, child anchor=children}{}
    },
  },
}
\begin{document}
\begin{forest}
  my tree
    [A
      [B1
       [
          [D1
            [E1]
            [E2]
          ]
          [D2
            [E3]
            [E4]          
          ]
       ]
      ]
      [B2
        [C2
          [D3
            [E5]
            [E6]          
          ]
          [D4
            [E7]
            [E8]          
          ]
        ]
      ]
    ]
\end{forest}
\begin{forest}
  my tree,
    [A
      [B1
        [
          [D1
            [E1]
            [E2]
          ]
          [D2
            [E3]
            [E4]
          ]
          [D3
            [E5]
            [E6]
          ]
        ]
        [                        
          [D4
            [E7]
            [E8]
          ]
          [
            [E9]
            [E10]
          ]                                   
        ]                                     
      ]
      [B2
        [C3
          [D6
            [E11]
            [E12]
          ]
          [D7
            [E13]
            [E14]
          ]
        ]
      ]
    ]
\end{forest}
\end{document}

答案2

我不是森林专家,但我可以在森林手册中查找分叉边缘的定义,并用它来定义一个“新”版本,其中分叉到子级(而不是父级)的距离是固定的。编辑:已将 移出my forked edgesfor tree非常感谢@cfr!

\documentclass[12pt,crop=true,border=1cm]{standalone}
\usepackage[edges]{forest}
%\usetikzlibrary{calc}
\forestset{
  declare dimen={my fork sep}{0.5em},
  my forked edge'/.style={
    edge={rotate/.option=!parent.grow},
    edge path'={let \noexpand\p1=($(.child anchor)-(!u.parent anchor)$) in 
    (!u.parent anchor) -- ++(\noexpand\x1-\forestoption{my fork sep},0) |- (.child anchor)},
  },
  my forked edge/.style={
    on invalid={fake}{!parent.parent anchor=children},
    child anchor=parent,
    my forked edge',
  },
  my forked edges/.style={for nodewalk={#1}{my forked edge}},
  my forked edges/.default=tree,
}
\begin{document}

\begin{forest}
my forked edges,
  for tree={
    grow'=0,
    draw,
    my fork sep=8pt,
    text width=10mm,
    minimum height=5mm,
    parent anchor=east,
    child anchor=west,
    text centered,
  }
    [A,tier=level1
      [B1,tier=level2,name=B1
%        [C1 would be here, but it is missing
          [D1,tier=level4,name=D1
            [E1,tier=level5]
            [E2,tier=level5]
          ]
          [D2,tier=level4,name=D2
            [E3,tier=level5]
            [E4,tier=level5]          
          ]
%        ]
      ]
      [B2,tier=level2
        [C2,tier=level3
          [D3,tier=level4
            [E5,tier=level5]
            [E6,tier=level5]          
          ]
          [D4,tier=level4
            [E7,tier=level5]
            [E8,tier=level5]          
          ]
        ]
      ]
    ]
\end{forest}
\end{document}

在此处输入图片描述

相关内容