编辑

编辑

我想画如下的树:

所需树显示 http://quicklatex.com/cache3/ql_c0f6b5397c19caf09ce70d6e47841eb7_l3.png

也就是说,我有交叉的边。树应该像普通树一样绘制(没有交叉),除了最后一层,其中叶子可以按任何水平顺序排列。节点等的数量是任意的,图像只是一个例子。

我对这棵树唯一了解的是 (a) 它的结构,即节点及其子节点,以及 (b) 每片叶子的排序号 (=x 位置),它决定了叶子应该在水平方向上显示的位置以形成交叉点。在上面的例子中,我知道的a1是位置 0、b1位置 1、a2位置 2 和b2位置 3。当我绘制特定的叶子时,我可以使用这些数字。

代码必须表示树的结构,如下所示:

\documentclass[a4paper]{scrartcl}
\usepackage{tikz}
\usepackage{tikz-qtree}
\begin{document}
\begin{tikzpicture}
\tikzset{frontier/.style={distance from root=70pt}}
  \Tree [.Z [.\node{A};
                \node{a1};
                \node{a2}; ]
              [.\node{B};
                \node{b1};
                \node{b2}; ] ]
\end{tikzpicture}
\end{document}

生成结果:

非交叉树显示http://quicklatex.com/cache3/ql_4217cf1d35018cf2016b55ac580d6085_l3.png

理想情况下,现在我想根据我所知道的排序号对叶子进行重新排序:

  \Tree [.Z [.\node{A};
                \node at (0,0) {a1};
                \node at (2,0) {a2}; ]
              [.\node{B};
                \node at (1,0) {b1};
                \node at (3,0) {b2}; ] ]

问题是,这会变成:

错误的树 http://quicklatex.com/cache3/ql_8b543330e2e251476b91100f13dcca4a_l3.png

问题:如何实现叶子的重新定位而不失去自动树布局功能tikz-qtree

一些背景知识:这些是由所谓的多重上下文无关语法递归生成的派生树,可以模拟 a^ib^ja^ib^j 等语言。我在终端后附加了数字,以便更明确地说明它们在重新排序后最终会出现在哪里。

答案1

你想要这样的东西吗?

请注意,我根本不确定我是否理解您要做什么。

在您对 Gonzalo Medina 的回答的评论中,您说您知道“a”必须出现在位置 0 和 2,而“b”必须出现在位置 1 和 3。但不清楚您希望如何实现自动化。(TeX 如何区分 1 个“a”和另一个“a”?您的示例代码中没有输入词“abab”,因此似乎没有以任何形式提供此信息。)

forest允许您创建“动态”树,即您可以在各个阶段移动内容。在这里,我在计算树的布局之后但在绘制之前移动节点:

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

\begin{document}
  \begin{forest}
    for tree={
      parent anchor=south,
      child anchor=north,
      where n children=0{
        s sep=1.5em,
        inner xsep=0pt
      }{},
    }
    [Z
      [A
        [a1
        ]
        [a2, before drawing tree={x+=1.5em}
        ]
      ]
      [B
        [b1, before drawing tree={x-=1.5em}
        ]
        [b2
        ]
      ]
    ]
  \end{forest}
\end{document}

布局计算后移动节点

编辑

OP 编辑​​了这个问题,以根据我上面的回答和评论中的讨论展示解决方案。但是,该解决方案需要手动指定叶节点的总数。我思考以下内容应避免此要求。想法是为每个叶节点增加一个 LaTeX 计数器,然后使用此计数器的最终值在绘制树之前调整节点的位置。leaf position定义了一种新样式,它接受一个参数,该参数应该是节点在有序序列中的位置,即leaf position=2如果叶子应该最终位于第三个(数字 2)位置。

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

\begin{document}

\begingroup

\newcounter{leafnodes}
\setcounter{leafnodes}{0}
\forestset{
  leaf position/.style={
    before drawing tree={
      where n children=0{
        x/.pgfmath={(#1-(.5*\theleafnodes)+.5)*1.5em}
      }{},
    }
  },
}
\begin{forest}
  for tree={
    parent anchor=south,
    child anchor=north,
    where n children=0{
      s sep=1.5em,
      inner xsep=0pt,
      delay={TeX={\stepcounter{leafnodes}}},
    }{},
  },
  [Z
    [A
      [a1, leaf position=0
      ]
      [a2, leaf position=2
      ]
    ]
    [B
      [b1, leaf position=1
      ]
      [b2, leaf position=3
      ]
    ]
  ]
\end{forest}
\endgroup

\end{document}

自动计算叶节点总数

编辑 编辑

为了回应评论中的讨论,这里有一个示例,它使用 将所有叶节点放在同一级别,tier=leaves并将这些节点的高度设置为标准大小,以便从父节点绘制的边不会终止于不同的高度。我还将最左边的节点向左移动了一点,因为它在较大的树中看起来有点奇怪。显然,如果需要,可以进一步调整。

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

\begin{document}

\begingroup

\newcounter{leafnodes}
\setcounter{leafnodes}{0}
\forestset{
  leaf position/.style={
    before drawing tree={
      where n children=0{
        x/.pgfmath={(#1-(.5*\theleafnodes))*1.5em}
      }{},
    }
  },
}
\begin{forest}
  for tree={
    parent anchor=south,
    child anchor=north,
    where n children=0{
      s sep=1.5em,
      inner xsep=0pt,
      tier=leaves,
      text height=5pt,
      delay={TeX={\stepcounter{leafnodes}}},
    }{},
  },
  [Z
    [A
      [A
        [A
          [T, leaf position=6
          ]
          [y, leaf position=1
          ]
          [e, leaf position=0
          ]
        ]
        [a, leaf position=5
        ]
        [a, leaf position=4
        ]
      ]
      [a1, leaf position=8
      ]
      [a2, leaf position=2
      ]
    ]
    [B
      [b1, leaf position=7
      ]
      [b2, leaf position=3
      ]
    ]
  ]
\end{forest}
\endgroup

\end{document}

平叶

答案2

如果你愿意转向强大的forest包,这可以轻松完成:

\documentclass[a4paper]{scrartcl}
\usepackage{forest}

\begin{document}

\begin{forest}
for tree={
  parent anchor=south,
  child anchor=north,
  l sep=0.75cm
}
[Z,s sep=-40pt
  [A,calign=fixed edge angles,calign primary angle=-30,calign secondary angle=60
    [a1]
    [a2]
  ]
  [B,calign=fixed edge angles,calign primary angle=-60,calign secondary angle=30
    [b1]
    [b2]
  ]
]
\end{forest}

\end{document}

在此处输入图片描述

答案3

源自cfr的原始答案和评论:

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

\begin{document}

\begingroup

\def\f{1.5em} % scale
\def\n{4} % number of leaves

\def\xleaf#1{\f*(#1-\n/2+0.5)} % calculates x of a leaf
\begin{forest}
  for tree={
    parent anchor=south,
    child anchor=north,
    where n children=0{
      s sep=1.5em,
      inner xsep=0pt
    }{},
  }
  [Z
    [A
      [a1, before drawing tree={x=\xleaf{0}}
      ]
      [a2, before drawing tree={x=\xleaf{2}}
      ]
    ]
    [B
      [b1, before drawing tree={x=\xleaf{1}}
      ]
      [b2, before drawing tree={x=\xleaf{3}}
      ]
    ]
  ]
\end{forest}
\endgroup

\end{document}

我想这就是它所能达到的极限了。虽然它需要叶子的总数,但我觉得从树中自动得出这个数字然后在表达式中使用它太复杂了before drawing tree

注意:cfr 的更新答案现在可以计算叶子了!

相关内容