Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

Is there a way to construct a tree whose children are located at specified positions, so that TikZ computes the locations of the other nodes in the tree based on the level distance and sibling distance?

I ask because, ultimately, I have a matrix of nodes and would like to grow a tree into the second column's vector from the righthand side. A minimal working example of what I have so far is:

\documentclass{standalone}
\usepackage{tikz}

\usetikzlibrary{positioning,matrix}

\begin{document}

\tikzset{
  img/.initial={},
  img/.value required,
  %
  image placeholder/.style={%
    execute at end node=\phantom{\pgfuseimage{\pgfkeysvalueof{/tikz/img}}}}
}

\pgfdeclareimage[height=7em]{ballot}{fptp-ballot}

\begin{tikzpicture}[every node/.style={draw=black},
                    every matrix/.style={ampersand replacement=\&}]
  \matrix (ballot counts)
          [matrix of nodes, nodes in empty cells, cells={right},
           column 1/.append style={%
             nodes={scale=0.5}, image placeholder, img=ballot}]
  {
    \& Alice: $0$ \\
    \& Bob: $0$ \\
    \& Charlie: $0$ \\
    \& Dave: $0$ \\
  };

  \matrix (ballot box)
          [node distance=2 and 2, right=of ballot counts,
           matrix of nodes, nodes in empty cells,
           cells={image placeholder, img=ballot}]
  {
    \& \\
    \& \\
  };

  \matrix (max tree)
          [matrix anchor=west]
          at (ballot counts.east)
  {
    \node {root} [grow=left, level/.style={sibling distance=7em/#1}]
      child {node {left}
        child {node {}}
        child {node {}}}
      child {node {right}
        child {node {}}
        child {node {}}}; \\
  };
\end{tikzpicture}

\end{document}

minimal working example of progress toward tree growing into matrix

I would like to modify this diagram so that the leaves of max tree attach to the four entries in second column of ballot counts (i.e., Alice: 0, ...).

In an earlier version of this question, @TomBombadil suggested that I could use at to explicitly position the leaves of the tree. The problem with that is that then the interior nodes will also have to be positioned explicitly. I was hoping for some way to leverage level distance and sibling distance.

Edit: Based on @percusse's comment that "growing the tree and putting nodes left of each sibling" might be an answer, I came up with the following MWE that does, more or less, what I want. (@percusse: Is this what you were getting at, or were you thinking something different?)

\documentclass{standalone}
\usepackage{tikz}

\usetikzlibrary{calc,positioning,matrix,fit}

\begin{document}

\tikzset{
  img/.initial={},
  img/.value required,
  %
  image placeholder/.style={%
    execute at end node=\phantom{\pgfuseimage{\pgfkeysvalueof{/tikz/img}}}}
}

\pgfdeclareimage[height=7em]{ballot}{fptp-ballot}

\tikzstyle{ballot count} = [matrix of nodes, nodes in empty cells,
                            right, inner sep=0em,
                            cells={right, inner sep=0.3333em},
                            column 1/.append style={%
                              image placeholder, img=ballot, nodes={scale=0.5}}]

\begin{tikzpicture}[every node/.style={draw},
                    every matrix/.style={ampersand replacement=\&}]
  % Construct a fake ballot count ``leaf'' to measure its height.
  \matrix (tmp) [ballot count, overlay, 
                 draw=none, nodes={draw=none}]
  { \\ };

  % Measure the height of the fake ``leaf''.
  \path let \p{childheight} = ($(tmp.north)-(tmp.south)$) in
    % Use the height to set sibling distance so that
    % there is no gap between the leaves of the tree.
    [level/.append style={sibling distance=2*\y{childheight}/#1,
                          level distance=2cm*#1}]
    node {root} [grow=left]
      child {node {left}
        child [child anchor=east] foreach \name in {Alice, Bob}
          {node (\name's count) [matrix, ballot count]
             { \& \name: $0$ \\ }}}
      child {node {right}
        child [child anchor=east] foreach \name in {Charlie, Dave}
          {node (\name's count) [matrix, ballot count]
             { \& \name: $0$ \\ }}};

  % Build the bounding box that contains all leaves.
  \node (ballot counts)
        [inner sep=0em, 
         fit=(Alice's count) (Bob's count)
             (Charlie's count) (Dave's count)] {};

  % Position a matrix to the right of the leaves.
  \matrix (ballot box)
          [node distance=2 and 2, right=of ballot counts,
           matrix of nodes, nodes in empty cells,
           cells={image placeholder, img=ballot}]
  {
    \& \\
    \& \\
  };
\end{tikzpicture}

\end{document}

enter image description here

This approach has several drawbacks:

  1. I have to create a fake leaf, named tmp, to measure the height of an arbitrary leaf. It would be better if I could somehow measure the height of a leaf and then retroactively pass this height to the sibling distance for the tree.

  2. Since the leaves are no longer within a matrix, I have to explicitly construct a bounding box in order to position ballot box where I want it to be. Also, the code for the leaves is now spread among the two subtrees; this complicates the description of the tree edges and non-leaf nodes, and requires that some of the code is duplicated across subtrees.

I guess, in general, the code is not as clean as I would have liked; I'm still hoping that there is a cleaner solution. But perhaps I just need to learn to be less greedy. :)

share|improve this question
    
you may find some informations about that in this thread –  sylcha Jun 9 '12 at 0:49
    
i use another comment because it is too late to edit the last one. you'll find the same problem here and i used something like you do but with barycentric cs. when you are stuck with the positions of the children nodes, i don't know how to do using the tree library unfortunatelly. it would be cool if we could build the tree from the roots, instead of the head... does someone know how to do so? –  sylcha Jun 9 '12 at 1:00
    
I think your ultimate goal might be doable but this one is more difficult... Can you give an example of the tree you want to grow? –  percusse Jun 10 '12 at 12:10
    
@percusse I have edited my question to describe my ultimate goal. Hopefully it is indeed doable. Thanks for your help. –  Henry DeYoung Jun 20 '12 at 21:00
    
So the level 2 nodes should be aligned with names and the level 1 nodes should be in the middle of the two names vertically, am I right? –  percusse Jun 20 '12 at 22:30
show 7 more comments

1 Answer

You can name nodes and then use these names for relative positioning. You can also use absolute position and do all the stuff you usually do with nodes. In the example, the automatically positiones node is red, the relative ones are blue:

\documentclass[parskip]{scrartcl}
\usepackage[margin=15mm]{geometry}
\usepackage{tikz}
\usetikzlibrary{trees,fit,shapes,calc}

\begin{document}

\begin{tikzpicture} 
\tikzstyle{level 1}=[sibling distance=40mm] 
\tikzstyle{level 2}=[sibling distance=20mm] 
\tikzstyle{level 3}=[sibling distance=10mm] 
 \node (S) {S} 
      child{node {N}  child{node (M1) {mary}} }
      child{node {VP}     
            child{node[fill=red,circle,text=green] (V) {V} child{node{brought }}}
            child{node[fill=blue,text=yellow,circle] (NP2) at ($(V)+(2,-2)$) {NP}  child{node{D} child{node (A2){a}}} child{node{N} child{node (C2) {cat}}}  }
            child{node[fill=blue,text=yellow,circle] (PP) at ($(NP2)+(4,1)$) {PP}  child{node{IN} child{node{to}}}     child{node{N}  child{node{school}}} }                          }
;
\end{tikzpicture}

\end{document}

enter image description here

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.