绘制 PQ 树

绘制 PQ 树

我需要在 LaTeX 中绘制如下所示的 PQ 树:

http://i.imgur.com/D4cIk0x.png

我尝试在 tikz 中使用树,但遇到了两个问题:

  • 部分阴影矩形
  • 如果父级是矩形,则使用从子级到父级的垂直指针

我想知道 tikz-trees 是否是最简单的方法,或者您是否建议使用其他方法?

答案1

该解决方案使用forest包用于放置节点。这样做的好处是它们可以自动定位,不会重叠。

对于节点我定义了三种样式:

  • tria对于三角形节点,它使用形状isosceles triangle(可以指定宽度和高度);
  • rect对于矩形节点,作为参数,它需要其子节点的数量(包括节点),以便它可以正确地拉伸并覆盖其子节点的宽度;
  • circ为圆形节点;
  • dots对于包含的节点\ldots,通过键(一个键)\ldots给出。contentforest

此外,

  • patt用于通过选项仅对形状的一部分进行图案化path picture;当我使用 TikZ 版本(坐标@aux1@aux2位于默认中心)遇到问题时,此版本的(更快更方便)PGF 版本有效。参数是<start of the pattern>:<end of the pattern>,即水平比率。

  • 用于*|仅绘制一条垂直线到父节点(这实际上可以包含在样式中rect)。

  • normal width和键的值normal height用于节点的大小。


rect风格上可以找到

minimum width=
     (#1  )*(\pgfkeysvalueof{/forest/normal width})
   + (#1+1)*(\forestove{s sep})
   - (#1  )*(\pgfkeysvalueof{/pgf/outer xsep})

效果很好,尽管我最初的设置不同

rect样式获得子元素的数量时#1,宽度设置为#1 * width占子元素总宽度的数。到目前为止一切顺利。我最初在这里乘以#1 - 1s sep六个子元素之间有五个空格),虽然#1 + 1看起来更正确,否则子元素或多或少会突出角度的水平边rect(或者rect不如其子元素宽)。

节点之间的间距似乎还有更多问题。如果设置不同的normal widthnormal height值,则间距会受到影响。我怀疑节点的高度会以某种方式影响s sep节点之间的水平间距。

进一步改进……

…可以通过自动化流程来实现。三角形节点只与它们之间的点成对出现,然后以相同的方式形成图案。

另外,forest可能还具有提前读取孩子的数量的功能,以便rect自动设置角度的宽度。

代码

\documentclass[tikz,convert=false]{standalone}
\usepackage{forest}
\usetikzlibrary{shapes.geometric,patterns}
\forestset{
  *|/.style={
    parent anchor=south,
    for descendants={
      edge path={
        \noexpand\path[\forestoption{edge}]
        (!u.parent anchor-|.child anchor) -- (.child anchor)\forestoption{edge label};
      }
    }
  },
  normal width/.initial=.5cm,
  normal height/.initial=.5cm,
  every forest node/.style={
    draw,
    minimum width=\pgfkeysvalueof{/forest/normal width},
    minimum height=\pgfkeysvalueof{/forest/normal height},
    inner sep=+0pt,
    anchor=south,
  },
  tria/.style={
    every forest node,
    shape=isosceles triangle,
    shape border rotate=90,
    isosceles triangle apex angle=60,
%    isosceles triangle stretches=true
  },
  rect/.style={
    every forest node,
    shape=rectangle,
    minimum width=(#1)*(\pgfkeysvalueof{/forest/normal width})+(#1+1)*(\forestove{s sep})-(#1)*(\pgfkeysvalueof{/pgf/outer xsep}),
  },
  rect/.default=3,
  circ/.style={
    every forest node,
    shape=circle
  },
  dots/.style={
    no edge,
    content=\ldots,
    every forest node,
    shape=rectangle,
    draw=none,
  },
  patt/.style args={#1:#2}{
    node options={
      /tikz/path picture={
        \pgfsetfillpattern{north east lines}{black}
        \pgfpathrectanglecorners
          {\pgfpointlineattime{#1}
            {\pgfpointanchor{path picture bounding box}{north west}}
            {\pgfpointanchor{path picture bounding box}{north east}}}
          {\pgfpointlineattime{#2}
            {\pgfpointanchor{path picture bounding box}{south west}}
            {\pgfpointanchor{path picture bounding box}{south east}}}
         \pgfusepath{fill}
%      \draw[green,ultra thick] (path picture bounding box.north west) -- coordinate[pos={#1}] (@aux1) (path picture bounding box.north east)
%                               (path picture bounding box.south west) -- coordinate[pos={#2}] (@aux2) (path picture bounding box.south east);
%      \fill[draw,pattern=north east lines] (@aux1) rectangle (@aux2);
%%      \fill[blue] (@aux1) circle (2pt);
%%      \fill[red] (@aux2) circle (1pt);
      }
    }
  },
  patt/.default=0:1
}
\begin{document}
\begin{forest} for tree={child anchor=north}
  [,circ,
    [, tria]
    [, dots]
    [, tria]
    [, rect=6, patt=.5:1, *|, alias=XY
      [, tria]
      [, dots]
      [, tria]
      [, tria, patt]
      [, dots]
      [, tria, patt, alias=XX]
    ]
    [, tria, patt]
    [, dots]
    [, tria, patt]
    [, rect=6, patt=0:.5, *|
      [, tria, patt]
      [, dots]
      [, tria, patt]
      [, tria]
      [, dots]
      [, tria]
    ]
  ]
% just to show that they are aligned correctly
  \draw[opacity=.5] (XY.south east) -- (XX.right corner);
\end{forest}
\end{document}

输出

在此处输入图片描述

相关内容