如何修复这片森林中儿童的位置问题?

如何修复这片森林中儿童的位置问题?

我正在尝试将这片森林的分支 1 和 2 与字幕 1 和 2 下的垂直线对齐,但目前还无法做到这一点。您知道该怎么做吗?

我的森林图

该图是使用此代码制作的。在序言中:

\usepackage[linguistics]{forest}
\makeatletter
\csdef{forest@compute@node@boundary@rounded rectangle}{%
  \forest@mt{east}%
  \forest@lt{north east}%
  \forest@lt{north}%
  \forest@lt{north west}%
  \forest@lt{west}%
  \forest@lt{south west}%
  \forest@lt{south}%
  \forest@lt{south east}%
  \forest@lt{east}%
}
\makeatother

并在文件中:

\vspace{0.2cm}
\begin{center}
\begin{forest}
t1/.style={style={draw=black,text height=2.3ex,text depth=.85ex},rounded corners},
t2/.style={style={draw=black,text height=4.5ex,text depth=3ex},rounded corners},
t3/.style={style={draw=black,text height=6.6ex,text depth=5.0ex},rounded corners},
for tree={edge path={\noexpand\path[\forestoption{edge}] (\forestOve{\forestove{@parent}}{name}.parent anchor) -- +(0,-8pt)-| (\forestove{name}.child anchor)\forestoption{edge label};}
}
[Title, s sep=8mm,t1
 [Subtitle 1, s sep=8mm,t1
  [$\begin{array}{l} \bullet \\ \bullet \\ \bullet \end{array}$, s sep=8mm,t3
   [Branch 1, s sep=8mm,t1
    [$\begin{array}{l} \bullet \\ \bullet \end{array}$, s sep=8mm,t2]
   ]
   [Branch 2, s sep=8mm,t1
    [$\begin{array}{l} \bullet \\ \bullet \end{array}$, s sep=8mm,t2]
   ]
  ]
 ]
 [Subtitle 2, s sep=8mm,t1
  [$\begin{array}{l} \bullet \\ \bullet \end{array}$, s sep=8mm,t2]
 ]
]
\end{forest}
\end{center}

答案1

一个近似解决方案非常简单:添加calign=1到包含“Branches”的三重项目符号节点。此键将节点与第一个(因为1)子节点对齐;在我们的例子中,它将垂直对齐“Branch 1”与三重项目符号节点(因此是“Subtitle 1”)。如果“Subtitle”节点与“Branch”节点的宽度相同,这将完美地工作。由于情况并非如此,“Branch 2”看起来有点错位,所以我们需要开发另一个解决方案。

子节点相对于父节点的位置存储在s(给定树的生长方向,稍后将转换为坐标x)。因此,我们的想法是s从“字幕”节点复制到“分支”节点 — 这会将“字幕”之间的“水平距离”转移到“分支” — 然后从所有“分支”的中减去(s-s“字幕 1”的s— 这将使s“分支 1”为零,使其与父节点对齐,而所有其他“分支”节点将与其对应的“字幕”节点对齐。

我们先手动操作一下,相关代码可以在before computing xy“分支 1”和“分支 2”中找到。

\documentclass{article}

\usepackage[linguistics]{forest}
\makeatletter
\csdef{forest@compute@node@boundary@rounded rectangle}{%
  \forest@mt{east}%
  \forest@lt{north east}%
  \forest@lt{north}%
  \forest@lt{north west}%
  \forest@lt{west}%
  \forest@lt{south west}%
  \forest@lt{south}%
  \forest@lt{south east}%
  \forest@lt{east}%
}
\makeatother

\begin{document}

\vspace{0.2cm}

\begin{center}
  \begin{forest}
    t1/.style={style={draw=black,text height=2.3ex,text depth=.85ex},rounded corners},
    t2/.style={style={draw=black,text height=4.5ex,text depth=3ex},rounded corners},
    t3/.style={style={draw=black,text height=6.6ex,text depth=5.0ex},rounded corners},
    for tree={edge path={\noexpand\path[\forestoption{edge}] (\forestOve{\forestove{@parent}}{name}.parent anchor) -- +(0,-8pt)-| (\forestove{name}.child anchor)\forestoption{edge label};}
    }
    [Title, s sep=8mm,t1
      [Subtitle 1, s sep=8mm,t1
        [$\begin{array}{l} \bullet \\ \bullet \\ \bullet \end{array}$, s sep=8mm,t3,
          [Branch 1, s sep=8mm,t1,
            before computing xy={s/.option={!r1.s}, s-/.option={!r1.s}},
            [$\begin{array}{l} \bullet \\ \bullet \end{array}$, s sep=8mm,t2]
          ]
          [Branch 2, s sep=8mm,t1,
            before computing xy={s/.option={!r2.s}, s-/.option={!r1.s}},
            [$\begin{array}{l} \bullet \\ \bullet \end{array}$, s sep=8mm,t2]
          ]
        ]
      ]
      [Subtitle 2, s sep=8mm,t1
        [$\begin{array}{l} \bullet \\ \bullet \end{array}$, s sep=8mm,t2]
      ]
    ]
  \end{forest}
\end{center}

\end{document}

before computing xy时间传播子将密钥的执行延迟到树已经打包好的时刻(即,森林已经确定了每个节点的放置位置并将这个决定存储在节点的sl中),但在树布局转移到纸张坐标x和之前y

.option密钥处理程序告诉 Forest 给定的值应解释为选项名称,并且是相对选项名称。读!r1.s作:!表示“我们去散步”;r= 让我们去根节点;1= 让我们去第一个子节点;点将相对节点名称与选项名称分开;s是我们想要获取的选项。因此,s/.option={!r1.s}指示 Forest 采用s根节点的第一个子节点的选项并将其存储在s当前节点的选项中。

当然,当我们有许多节点需要处理时,手动方法使用起来很麻烦。下面,我们s一次调整所有“分支”的选项。相关代码可以在 中找到before computing xy,但现在这个时间传播器出现在三重子弹节点中,它是“分支”的父节点。

\documentclass{article}

\usepackage[linguistics]{forest}
\makeatletter
\csdef{forest@compute@node@boundary@rounded rectangle}{%
  \forest@mt{east}%
  \forest@lt{north east}%
  \forest@lt{north}%
  \forest@lt{north west}%
  \forest@lt{west}%
  \forest@lt{south west}%
  \forest@lt{south}%
  \forest@lt{south east}%
  \forest@lt{east}%
}
\makeatother

\begin{document}

\vspace{0.2cm}

\begin{center}
  \begin{forest}
    t1/.style={style={draw=black,text height=2.3ex,text depth=.85ex},rounded corners},
    t2/.style={style={draw=black,text height=4.5ex,text depth=3ex},rounded corners},
    t3/.style={style={draw=black,text height=6.6ex,text depth=5.0ex},rounded corners},
    for tree={edge path={\noexpand\path[\forestoption{edge}] (\forestOve{\forestove{@parent}}{name}.parent anchor) -- +(0,-8pt)-| (\forestove{name}.child anchor)\forestoption{edge label};}
    }
    [Title, s sep=8mm,t1
      [Subtitle 1, s sep=8mm,t1
        [$\begin{array}{l} \bullet \\ \bullet \\ \bullet \end{array}$, s sep=8mm,t3,
          before computing xy={
            for children={
              s/.process=Ow+O{n}{!r#1.s},
              s-/.option={!r1.s},
            },
          },
          [Branch 1, s sep=8mm,t1,
            [$\begin{array}{l} \bullet \\ \bullet \end{array}$, s sep=8mm,t2]
          ]
          [Branch 2, s sep=8mm,t1,
            [$\begin{array}{l} \bullet \\ \bullet \end{array}$, s sep=8mm,t2]
          ]
        ]
      ]
      [Subtitle 2, s sep=8mm,t1
        [$\begin{array}{l} \bullet \\ \bullet \end{array}$, s sep=8mm,t2]
      ]
    ]
  \end{forest}
\end{center}

\end{document}

空间传播器for children是不言自明的:它对每个子节点使用给定的选项。其中s-的第二行for children也很熟悉:它将s从根节点的第一个子节点中 减去s。第一行调用参数处理器需要.process解释——但要真正了解它是如何工作的,您还需要查阅手册第 3.13 节。

的值.process由两部分组成:指令(OwO)和参数({n}{!r#1.s})。

  • 第一条指令,O,告诉森林查找一个选项。哪个选项?它的名称在第一个参数中给出:n,该选项保存节点的子编号(“分支 1”和“字幕 1”有n=1;“分支 2”和“字幕 2”有n=2)。结果(的值n)。结果(当前节点处理争论。

  • 第二条指令是w:将第一个剩余参数包裹在最后处理的参数周围。在我们的例子中,第一个剩余参数是!r#1.s。它被视为宏定义,并被#1替换为最后处理的参数。假设我们处于“分支 2”:那么该指令的结果是!r2.s成为最后处理的参数。

  • 指令+使最后处理的参数成为第一个剩余的参数。

  • O再次查找第一个剩余参数中命名的选项;在我们的例子中是!r2.s。我们已经知道这是什么:s根的第二个子节点的,即s“Subtitle 2”的。然后,该值将成为最后处理的参数。

  • 没有其他指令,因此最后处理的参数,即s“字幕 2”的 ,存储在s当前节点的 中(因为s/.process)。(通常,所有处理过的参数加上剩余的参数都会传递给调用选项。)

简而言之,简短而复杂(至少在你习惯它之前:)。

相关内容