[pst-tree] Specific requirement on edges between tree nodes

Denis Girou Denis.Girou at idris.fr
Thu Mar 30 22:15:31 CEST 2000


-----------------------------------------------------------------------------
This is the PSTricks mailing list, devoted to discussions about computational
graphics in (La)TeX using the PSTricks package from Timothy van Zandt.
For help using this mailing list, see instructions at the end of message.
-----------------------------------------------------------------------------

  There was an interesting and non trivial question on trees yesterday on
fr.comp.text.tex. I just translate here my answer.

  The user would like to have nodes like a stack of short lines surrounded by 
a box (easy part), but with edges like this ones:

        /         |           \
       /          |            \
      /           |             \
     /            |              \
    /             |               \    <- edges at the middle of top boxes
  +---+         +---+            +---+ <- boxes aligned at top
  |   |         |   |            |   |
  |   |         |   |            |   |
  +---+         |   |            |   |
   /|\          |   |            +---+
  / | \         |   |             /|\  <- edges at the middle of bottom boxes
                +---+            / | \
                 /|\
                / | \

  The difficult part is the requirements on edges. In fact, this is not
possible directly (if ever I do not miss an obvious idea...).

  For PSTricks, a node is associated to each entry of a tree, and the links
between fathers and sons are later drawn by connections between these nodes,
from a type selected among the numberous ones available. In this case, when a
line is drawn from a father to a son, the connection point must be at top. But
when this son is himself a father, his connection point must be at this moment
at the bottom. So, we must have two different nodes for these entries, one for
the moment where it is used as a father and one another when it is used as a
son. But PSTricks define only one node for each entry.

  So, we must do some programmation:

  1/ First, we can't use the default position for nodes, which is at the
center of the boxes, at least with the \Tr nodes (version 1), but we must fix
it at the top of the boxes (version 2).

  2/ [ Even if this is not the original question, nevertheless we can notice
that the problem disappear if we replace the links as oblique lines by another 
common type of them (version 3), because in this case we can't see that the
connection point for the fathers is uncorrect, as the erroneous segments are
not drawn due to the box itself. This is a side effect, but in this case
favorable. And in fact, this is a very common practice, also because most
people find this kind of connections more aesthetic. ]

  3/ But if we come back to the initial problem, the solution is to define a
personal supplementary node for each of the fathers (version 4). The new nodes
are defined by \rnode[b], which allow to reference the bottom of the father
boxes. And before to define the sons, we change the name of the node which
define the connection point of the father of these sons (this is done by the
\renewcommand{\pspred}{...} commands).

  4/ The inconvenience is that we must specially make some treatment one time
for each father and one time for each group of sons, and also manage the new
names of the nodes. If we want to have things more transparent, we must know
some basis of TeX programmation and also me details about the internals of the
PSTricks trees. The first thing to simplify is to generate automatically the
names of the new nodes (version 5). For this, we index these names by the
level of their father in the hierarchy.
     Here, I also define the new nodes with \Rnode commands, because in this
case we will have more flexibility that with \rnode, because the "vref"
parameter allow to externally modify the exact vertical position of the nodes
(relatively to the reference point, which is on the baseline of the last line
for the entry - notice that with \rnode[b], the frame of the box is taken into 
account).

  5/ If we want to have a completely transparent solution, we must redefine
what is a tree (version 6). In the case of the fathers, we must activate a
definition of the node which really define two nodes, as explained earlier.
And in the case of the sons, we must come back to the normal definition of a
node and redefine the connection point of their father, by changing the name
of the node used. All of that only require a dozen of lines of code, but
also require some experiment in TeX + PSTricks programming.

D.G.


\documentclass{article}

\usepackage{pst-tree}

\pagestyle{empty}

\begin{document}

% Version 1
% ---------

\newcommand{\MyNode}[1]{\Tr{\psframebox{#1}}}

\pstree{\MyNode{A}}
       {\MyNode{B}
        \MyNode{\shortstack{BB\\B}}
        \pstree{\MyNode{\shortstack{BBB\\BB\\B}}}
               {\MyNode{C}
                \MyNode{CC}
                \MyNode{CCC}}}

% Version 2
% ---------

\renewcommand{\MyNode}[1]{\Tr[ref=t]{\psframebox{#1}}}

\vspace{1cm}
\pstree{\MyNode{A}}
       {\MyNode{B}
        \MyNode{\shortstack{BB\\B}}
        \pstree{\MyNode{\shortstack{BBB\\BB\\B}}}
               {\MyNode{C}
                \MyNode{CC}
                \MyNode{CCC}}}

% Version 3
% ---------

\begingroup
\renewcommand{\psedge}[2]{\ncangles[angleA=-90,angleB=90]{#1}{#2}}

\vspace{1cm}
\pstree{\MyNode{A}}
       {\MyNode{B}
        \MyNode{\shortstack{BB\\B}}
        \pstree{\MyNode{\shortstack{BBB\\BB\\B}}}
               {\MyNode{C}
                \MyNode{CC}
                \MyNode{CCC}}}
\endgroup

% Version 4
% ---------

\renewcommand{\MyNode}[2][]{\Tr[ref=t]{#1{\psframebox{#2}}}}

\vspace{1cm}
\pstree{\MyNode[{\rnode[b]{PredA}}]{A}}
       {\renewcommand{\pspred}{PredA}%
        \MyNode{B}
        \MyNode{\shortstack{BB\\B}}
        \pstree{\MyNode[{\rnode[b]{PredB}}]{\shortstack{BBB\\BB\\B}}}
               {\renewcommand{\pspred}{PredB}%
                \MyNode{C}
                \MyNode{CC}
                \MyNode{CCC}}}

% Version 5
% ---------

\makeatletter

\newcommand{\MyRootNode}[1]{%
\Tr[ref=t]{\Rnode{Pred\romannumeral\pstreelevel}{\psframebox{#1}}}}
\newcommand{\UpdateRootNode}{%
\pst at cnta=\pstreelevel
\advance\pst at cnta\m at ne
\def\pspred{Pred\romannumeral\pst at cnta}}

\makeatother

\vspace{1cm}
\begingroup
\psset{vref=0}
\pstree{\MyRootNode{A}}
       {\UpdateRootNode%
        \MyNode{B}
        \MyNode{\shortstack{BB\\B}}
        \pstree{\MyRootNode{\shortstack{BBB\\BB\\B}}}
               {\UpdateRootNode%
                \MyNode{C}
                \MyNode{CC}
                \MyNode{CCC}}}
\endgroup

% Version 6.a
% -----------

\makeatletter

\let\pstreeORIG\pstree

\def\pstree{\@ifnextchar[{\pstreeMOD at i}{\pstreeMOD at i[]}}

\def\pstreeMOD at i[#1]{\pstreeMOD at ii[#1]}

\def\pstreeMOD at ii[#1]#2#3{\pstreeMOD at iii[#1]#2\@nil#3\@nil}

\def\pstreeMOD at iii[#1]#2\@nil#3\@nil{%
\pstreeORIG[#1]{%
\def\MyNode##1{%
\Tr[ref=t]{\Rnode{Pred\romannumeral\pstreelevel}{\psframebox{##1}}}}%
#2}{%
\def\MyNode##1{\Tr[ref=t]{\psframebox{##1}}}%
\pst at cnta=\pstreelevel
\advance\pst at cnta\m at ne
\def\pspred{Pred\romannumeral\pst at cnta}%
#3}}

\makeatother

\vspace{1cm}
\pstree{\MyNode{A}}
       {\MyNode{B}
        \MyNode{\shortstack{BB\\B}}
        \pstree{\MyNode{\shortstack{BBB\\BB\\B}}}
               {\MyNode{C}
                \MyNode{CC}
                \MyNode{CCC}}}

% Version 6.b
% -----------

\vspace{1cm}
\begingroup
\psset{vref=0}
\pstree{\MyNode{A}}
       {\MyNode{B}
        \MyNode{\shortstack{BB\\B}}
        \pstree{\MyNode{\shortstack{BBB\\BB\\B}}}
               {\MyNode{C}
                \MyNode{CC}
                \MyNode{CCC}}}
\endgroup

% Version 6.c
% -----------

\vspace{1cm}
\begingroup
\psset{vref=-0.1}
\pstree{\MyNode{A}}
       {\MyNode{B}
        \MyNode{\shortstack{BB\\B}}
        \pstree{\MyNode{\shortstack{BBB\\BB\\B}}}
               {\MyNode{C}
                \MyNode{CC}
                \MyNode{CCC}}}
\endgroup

\end{document}

-----------------------------------------------------------------------------
The list interface (subscription, information, access to the archives) is on:
http://www.tug.org/cgi-bin/lwgate/pstricks
Otherway to unsubscribe, send mail to pstricks-request at mail.tug.org
with a blank subject and in body the line unsubscribe <email-address>
-----------------------------------------------------------------------------



More information about the PSTricks mailing list