买者自负...

买者自负...

在森林中的多行模式 ( align=center) 下,节点周围有额外的垂直空间。下面的第一棵树不是多行模式。第二棵树是多行模式,节点文本上方和下方都有额外的空间,即使只有一行。我怎样才能让第二棵树看起来像第一棵树?(我的实际树中的许多节点确实有多行,这就是我使用多行的原因。)

\documentclass{standalone}
\usepackage{forest}
\begin{document}
\begin{forest}
[A, for tree={parent anchor=south, child anchor=north, draw}
  [B]
  [C
    [D]
    [E]
  ]
]
\end{forest}

\begin{forest}
[A, for tree={parent anchor=south, child anchor=north, align=center, draw}
  [B]
  [C
    [D]
    [E]
  ]
]
\end{forest}
\end{document}

第一棵树有方形节点。所有节点都对齐 = 中心的树有矩形节点,节点文本的顶部和底部有额外空间。

我尝试减少inner ysep,它最初似乎有帮助(节点文本周围的空间较小但仍然偏离中心),但后来我遇到了一些节点重叠的问题:

\documentclass{standalone}
\usepackage{forest}
\begin{document}
\begin{forest}
[A, for tree={draw, parent anchor=south, child anchor=north, align=center, inner ysep=1pt }
  [B\\long node]
  [C
    [D\\long multiline, triangle]
  ]
]
\end{forest}
\end{document}

多线节点与另一个多线节点的三角形重叠。

我还应该提到,我没有使用方框draw来框住真实树中的节点,只是使用裸节点文本。我在这里使用它是因为它可以清楚地表明,问题在于节点大小,而不是边缘位置。这个额外的空间使边缘看起来离节点更远,而不是节点更高。

答案1

这是一个 hack。它提供了照原样没有任何保证。我甚至不保证它与森林、多行节点或 TeX。在这一点上,如果不清楚,我应该声明我什么都不保证。如果代码拨打了 CIA、MI5 和 KGB 的电话,并向他们提供你的猫以换取一管 Smarties,不要说我没有警告过你。

买者自负...


想法如下:

  • 如果我们将 放入tabular未使用align来创建多行节点的树中的节点中,我们将获得与使用 相同的结果align。但是,tabular本身不会添加垂直空间,因此我们不能将该空间设置为 0,因为它已经为零。

  • 如果我们将 放入minipage同一棵树中的节点中,则间距与将 的内容单独放入节点中相同minipage。(假设节点只有一行。)

  • 因此,如果我们可以将多行节点创建为minipages 而不是tabulars,那么它就可以按预期工作。(亲爱的读者,是否符合预期,就留给您自己决定吧。)

这并不像听起来那么简单,因为minipage与 不同,tabular需要宽度,而我们不想为树中的所有节点设置宽度。

当然,有更简单的方法可以做到这一点,而且毫无疑问还有更有效的方法。尤其是 TeX 专家可能会做得更好。

在这一点上,请温柔的读者再次阅读上面有关保证以及对所有读者的猫(无论多么温柔)的危险的声明。

猫离家出走

我们首先为squat multiline这种树创建一种新样式:

\forestset{
  squat multiline/.style={

我们需要一些定制森林选项:

    declare dimen={thiswidth}{0pt},
    declare autowrapped toks={thiscontent}{},

现在我们开始操作节点。我们循环执行此操作,以确保在为每个节点处理下一组密钥之前,为每个节点处理完每组密钥。

    for tree={
      delay={

这是第一轮:

        thiscontent/.wrap pgfmath arg={##1}{content()},

实际上,这会保存节点的内容。基本上,它会复制它。我们延迟此操作,否则当我们尝试复制它时,内容将不会被设置。

      },

现在进入下一轮:

      delay+={
        content/.wrap value={\begin{tabular}{@{}c@{}}##1\\\end{tabular}},

这会将内容包装在tabular类似于 使用的环境中align=center。我们将使用它来获取 的宽度minipage

        typeset node,

我们现在排版节点,比平时更早,因为接下来我们需要获取宽度。

      },

决赛轮:

      before typesetting nodes={

我们thiswidth使用节点当前的宽度进行设置。

        thiswidth/.wrap pgfmath arg={##1}{int(abs(max_x()-min_x()))},

minipage现在我们重置宽度为 的a 中节点的内容thiswidth。我们使用来自的内容的副本,thiscontent因为否则我们也会得到tabular包装器。

        content/.wrap pgfmath arg={\begin{minipage}[t]{\dimexpr\forestove{thiswidth}}\centering ##1\end{minipage}}{thiscontent()},

我们已经得到了一批,inner xsep因为它在我们最初排版节点时就已包含。因此我们将其设置为 0,以避免得到两倍于通常的数量:

        inner xsep=0pt,

我们需要告诉森林重新排版节点:

        typeset node,
      },

只是原始示例中的常见锚点:

      parent anchor=south,
      child anchor=north,
    },
  }
}

现在我们可以使用新的样式了。第一个例子比较了默认间距与squat multiline节点内容相同时使用的间距:

\begin{forest}
  for tree={draw}
  [, phantom
    [A, for tree={parent anchor=south, child anchor=north}
      [B]
      [C
        [D]
        [E]
      ]
    ]
    [A, squat multiline
      [B]
      [C
        [D]
        [E]
      ]
    ]
  ]
\end{forest}

间距比较

然后是具有较大节点和屋顶的示例:

\begin{forest}
  for tree={draw},
  squat multiline
  [A,
    [B\\long node]
    [C
      [D\\long multiline, triangle]
    ]
  ]
\end{forest}

更复杂的情况

这种风格似乎并不是造成这里屋顶轻微错位的原因,当我将默认风格与绘制的节点进行比较时,也遇到了同样的问题。

比较:

树 1树 2

无论如何,我认为屋顶的组合不太draw可能是理想的,并且错位只会被注意到,因为节点是为了说明目的而绘制的。

完整代码:

\documentclass[multi,tikz,border=10pt]{standalone}
\usepackage{forest}
\begin{document}
\forestset{
  squat multiline/.style={
    declare dimen={thiswidth}{0pt},
    declare autowrapped toks={thiscontent}{},
    for tree={
      delay={
        thiscontent/.wrap pgfmath arg={##1}{content()},
      },
      delay+={
        content/.wrap value={\begin{tabular}{@{}c@{}}##1\\\end{tabular}},
        typeset node,
      },
      before typesetting nodes={
        thiswidth/.wrap pgfmath arg={##1}{int(abs(max_x()-min_x()))},
        content/.wrap pgfmath arg={\begin{minipage}[t]{\dimexpr\forestove{thiswidth}}\centering ##1\end{minipage}}{thiscontent()},
        inner xsep=0pt,
        typeset node,
      },
      parent anchor=south,
      child anchor=north,
    },
  }
}
\begin{forest}
  for tree={draw}
  [, phantom
    [A, for tree={parent anchor=south, child anchor=north}
      [B]
      [C
        [D]
        [E]
      ]
    ]
    [A, squat multiline
      [B]
      [C
        [D]
        [E]
      ]
    ]
  ]
\end{forest}
\begin{forest}
  for tree={draw},
  squat multiline
  [A,
    [B\\long node]
    [C
      [D\\long multiline, triangle]
    ]
  ]
\end{forest}
\end{document}

相关内容