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.

Relatively simple problem: I want to use macros to define substructures of a tree. In the following example for illustration, I want to define some children (left and right) to be used several times in a tree.

\documentclass{article}
\usepackage{tikz}

\begin{document}
  \begin{tikzpicture}

   \newcommand{\leftchildren}{%
     child{node[circle,draw] {l}} child{node[circle,draw] {l}} %
   }%

   \newcommand{\rightchildren}{%
     child{node[circle,draw] {r}} child{node[circle,draw] {r}} %
   }%

  \node[circle,draw] (root) {}  \leftchildren \rightchildren;
 \end{tikzpicture}
\end{document}

The problem is

  • Without the label (root) it does not even compile (Why?)

  • The macros are not expanded on the same level: the right children become children of the left children

  • Using more macros, or nesting them, makes it worse.

This is a very simplified version of what I want to do. Often I want to be able to add other children by hand (without using macro). I also would like to be able to define entire subtrees as macros, for example a long chain, as a macro.

I think there is a problem with the expansion of the macros, but I was not able to figure it out myself. Help please.

Cheers, Oliver

share|improve this question
    
Your suspicion is right, the macros should be expanded before node starts to read. From the manual: When a node operation like node {X} is followed by child, TikZ starts counting the number of child nodes that follow the original node {X}. For this, it scans the input and stores away each child and its arguments until it reaches a path operation that is not a child. –  percusse Jun 13 '12 at 11:41
    
And indeed, \expandafter\leftchildren\rightchildren does what I would expect your code to produce. –  Andrew Stacey Jun 13 '12 at 11:45
    
Which suggests to me that the right strategy would be to have a "tree building" command which expanded all the pieces before feeding it to TikZ. How complicated are your trees? Are there any macros in, say, the node texts? In the example one could do \edef\children{\leftchildren\rightchildren} but that wouldn't work if there was fancy stuff going on. –  Andrew Stacey Jun 13 '12 at 11:47
    
Oh, and for your first comment: the root node needs to have a name otherwise there's no way for TikZ to connect it to its children. The root node is processed before TikZ knows that it is constructing a tree so it doesn't know that that node is going to be used later and therefore it doesn't know to assign it a name automatically. With the internal nodes, TikZ knows that they are part of a tree so knows to give them names (if they don't already have them). –  Andrew Stacey Jun 13 '12 at 11:50
    
(And you now have enough reputation to post pictures. That's always helpful.) –  Andrew Stacey Jun 13 '12 at 11:50
show 1 more comment

3 Answers

This is similar to

macro for empty nodes in tikz-qtree

You need to pre-expand macros so the tikz parser sees them:

enter image description here

\documentclass{article}
\usepackage{tikz}

\begin{document}
  \begin{tikzpicture}

  \node[circle,draw] (root) {}  child{node[circle,draw] {l}} child{node[circle,draw] {l}} child{node[circle,draw] {r}} child{node[circle,draw] {r}};

 \end{tikzpicture}



aaaaaaaaaaaaaaaaa




  \begin{tikzpicture}

   \newcommand{\leftchildren}{%
     child{node[circle,draw] {l}} child{node[circle,draw] {l}} %
   }%

   \newcommand{\rightchildren}{%
     child{node[circle,draw] {r}} child{node[circle,draw] {r}} %
   }%

  \node[circle,draw] (root) {}  \leftchildren \rightchildren;
 \end{tikzpicture}


bbbbbbbbbbbbbbbbbbbbbbbbbbbb

\makeatletter

\let\mypgfutil@ifnch\pgfutil@ifnch
\def\pgfutil@ifnch{%
\let\x@next\@empty
\ifx\pgfutil@let@token\leftchildren\let\pgfutil@let@token c\let\x@next\expandafter\fi
\ifx\pgfutil@let@token\rightchildren\let\pgfutil@let@token c\let\x@next\expandafter\fi
\x@next\mypgfutil@ifnch}

\makeatother

   \newcommand{\leftchildren}{%
     child{node[circle,draw] {l}} child{node[circle,draw] {l}} %
   }%

   \newcommand{\rightchildren}{%
     child{node[circle,draw] {r}} child{node[circle,draw] {r}} %
   }%


  \begin{tikzpicture}


  \node[circle,draw] (root) {}  \leftchildren \rightchildren;
 \end{tikzpicture}

\end{document}
share|improve this answer
    
Thank you very much David. That is exactly what I suspected, but I was not able to achieve this expansion. To be honest, I understand almost nothing of the solution code you use to force the expansion ;-). But that is also not that important. I just need to understand what I need to do for more macros. I guess just adding a new line for each macro? Cheers, –  Oliver Jun 13 '12 at 12:59
    
yes the c in that line is the first token of the expansion, first letter of child in each case here. (It would be possible to rejig things so you didn't need to do that but....) –  David Carlisle Jun 13 '12 at 13:06
    
OK, I see. That is no problem. By the way, will this solution also work when the macros have parameters? –  Oliver Jun 13 '12 at 13:44
    
probably it'll work, if my understanding of what tikz is doing here is correct. I have almost no knowledge of tikz though:-) –  David Carlisle Jun 13 '12 at 14:09
    
Just an update from my side. David's solution also works for macros with parameters. Great! Thanks Ahmed for your suggestion, but I understand even less ;-). Never mind, I can live with the c character. (Even though it is easy to forget to change when you change the macro, happened already). Oliver –  Oliver Jun 14 '12 at 9:05
add comment

The character c is required to be always present in Master David Carlisle's approach. Here is an approach that I sometimes use.

\documentclass{article}
\usepackage{tikz}
\makeatletter
\newcommand*\tikzcommands{%
  % Collect your tikz commands here, otherwise they will be expanded
  % prematurely:
  \do\begin\do\end\do\coordinate\do\path\do\draw\do\node
}
\def\xtikzpicture{\@ifnextchar'{\@firstoftwo{\xtikz@picture{00}}}%
  {\xtikz@picture{01}}}
\def\xtikz@picture#1#2\end#3{%
  \def\reserved@a{#3}\def\reserved@b{xtikzpicture}%
  \ifx\reserved@a\reserved@b
    \def\endxtikzpicture{}%
    \end{xtikzpicture}%
  \else
    \@latexerr{Environment 'xtikzpicture' badly ended}\@ehd
  \fi
  \let\this@relax\relax
  \def\reserved@a##1\this@relax{}%
  \if#1\expandafter\reserved@a\fi
  \begingroup
  \def\do##1{\let##1\relax}\tikzcommands
  \protected@edef\x{\endgroup
    \begin{tikzpicture}#2\end{tikzpicture}%
  }\x
  \this@relax
}
\makeatother

\def\leftchildren{%
  child{node[circle,draw] {left}}
  child{node[circle,draw] {left}}
}
\def\rightchildren{%
  child{node[circle,draw] {\textcolor{blue}{right}}}
  child{node[circle,draw] {\textcolor{blue}{right}}}
}

\begin{document}
\begin{xtikzpicture}' % ignored
xx
\end{xtikzpicture}

\begin{xtikzpicture}[level distance=10mm,
  every node/.style={fill=red!40,circle,inner sep=1pt}]
  % Maybe someone can tell me why the circle on 'root' has no effect:
  \node {root} [grow'=up,circle,draw] 
  \leftchildren \rightchildren
  child {node {parent}
    child {node {child}}
    child {node {child}}
  };
\end{xtikzpicture}
\end{document}

enter image description here

share|improve this answer
add comment

You can also force expansion of your macro with \edef :

\edef\tmp{\leftchildren \rightchildren}
\node[circle,draw] (root) {} \tmp;
share|improve this answer
    
Welcome to TeX.sx! –  henrique Dec 14 '12 at 19:18
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.