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.

TL;DR Summary:

Is there some way to measure the width of a leaf node and pass this measurement back up the tree to be used in setting sibling distance? (One might want to do a similar thing for level distance as well.)

Example:

Suppose that I have a simple tree where the leaf nodes each contain the same image:

\documentclass{standalone}
\usepackage{tikz}

\pgfdeclareimage{image}{fptp-ballot}

\begin{document}
  \begin{tikzpicture}
    \node {root} [level/.append style={level distance=4cm}]
      child foreach \c in {1,2} {
        node [fill=red!10] {\pgfuseimage{image}}};
  \end{tikzpicture}
\end{document}

With the default setting for sibling distance, the leaves overlap:

enter image description here

One way that we could measure the width of the leaf is to create an invisible temporary leaf, tmp, and use the let operation for paths to compute its width:

\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{calc}

\pgfdeclareimage{image}{fptp-ballot}

\begin{document}
  \begin{tikzpicture}
    \node (tmp) [fill=red!10, transparent, overlay] {\pgfuseimage{image}};

    \path let \p{leafwidth} = ($(tmp.east)-(tmp.west)$) in
     node {root} [level/.append style={level distance=4cm, sibling distance=\x{leafwidth}}]
      child foreach \c in {1,2} {
        node [fill=red!10] {\pgfuseimage{image}}};
  \end{tikzpicture}
\end{document}

enter image description here

The problem with this approach is: It seems clumsy to need to create a temporary leaf, tmp, when the leaves that I really want to measure already exist later in the code. This makes things less modular. If I change the leaves, then I need to change the tmp node correspondingly (or factor out the leaf code with a macro and style).

In other words, I'd like a solution that works locally regardless of what I put inside the leaves -- a single image, a matrix with arbitrary cell content, etc.

Question:

Is there some way to directly measure the width of an actual leaf node and pass this measurement back up the tree to be used in setting sibling distance?

I would like to write something like the following:

\begin{tikzpicture}
  \node {root} [level/.append style={level distance=4cm, sibling distance=\x{leaf1width}}]
    child foreach \c in {1,2} {
      node (leaf\c)
         [fill=red!10] {\pgfuseimage{image}}
      let \p{leaf\c width} = ($(leaf\c.east)-(leaf\c.west)$) in};
\end{tikzpicture}

Here I am directly measuring the widths of the actual leaves and am trying to use this to set sibling distance at the root node. Unfortunately, this gives the error "Undefined control sequence. <argument> \x{leaf1width}", presumably because \p{leaf\c width} is not defined until the leaves are reached. Is there any way to fix this code?

I thought about using the late options key, but the TikZ manual states that

An already existing node is determined [...] and, then, the options are executed in a local scope. Most of these options will have no effect since you cannot change the appearance of the node, that is, you cannot change a red node into a green node using late options.

Indeed, the following compiles without error, but the sibling distance is not affected.

\begin{tikzpicture}
  \node (root) {root} [level/.append style={level distance=4cm}]
    child foreach \c in {1,2} {
      node (leaf\c)
           [fill=red!10] {\pgfuseimage{image}}
      let \p{leaf\c width} = ($(leaf\c.east)-(leaf\c.west)$) in
      (root) [late options={level/.append style={sibling distance=\x{leaf1width}}}]};
\end{tikzpicture}
share|improve this question
1  
I always use Yiannis' answer to get the size of the image: tex.stackexchange.com/a/3664/3235 You can first pass it through that solution get the relevant lengths and then start the TikZ part. –  percusse Aug 17 '12 at 22:26

1 Answer 1

As linked in the comments, putting your images to a box first makes it very easy to measure the size of the image. I am not sure that I understand the complication but if you have few images that would go into the tree then you can take the maximum of those measurements via max(x,y) from math library. Here I've stripped down the macros and used Yiannis' solution without any automation.

\documentclass{standalone}
\usepackage{tikz}

\newsavebox{\Image}
\savebox{\Image}{\includegraphics[scale=0.05]{DSOTM}}
\newlength{\imageh}
\newlength{\imagew}
\settoheight{\imageh}{\usebox{\Image}}
\settowidth{\imagew}{\usebox{\Image}}


\begin{document}
  \begin{tikzpicture}
    \node {root}  [level/.append style={
                      level distance=1.5\imageh, sibling distance=1.1\imagew
                      }
                  ]
      child foreach \c in {1,2} {
        node [fill=red!10,inner sep=1pt] {\includegraphics[scale=0.05]{DSOTM}}};
  \end{tikzpicture}
\end{document}

enter image description here

share|improve this answer
    
Thanks for pointing out Yiannis's image measurement macros; I hadn't seen it before and it will be useful. Unfortunately, though, it doesn't quite solve my problem, since I'd like the solution to work regardless of what I put inside the leaves -- a single image, a matrix with arbitrary cell content, etc. Also, I am hoping that the solution will local to the actual leaf, so that if I change the leaf contents, I don't need to remember to change something elsewhere (e.g. the saved box). I've edited my question to (hopefully) clarify. –  Henry DeYoung Aug 18 '12 at 16:05
    
Can you make this tree in Any Colour You Like? –  Tom Bombadil Aug 18 '12 at 17:49
1  
@TomBombadil :) with enough Brain Damage, Time, and, Money anything is possible! –  percusse Aug 18 '12 at 18:03
    
@HenryDeYoung Isee. I'll try to think something else –  percusse Aug 18 '12 at 19:16
    
@percusse Maybe it's not possible to measure the actual leaves and feed it back... Maybe the best thing is to factor out the leaf contents into a macro. I just thought it was worth asking if anyone had an idea. Thanks. –  Henry DeYoung Aug 18 '12 at 19:54

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.