17

I'm trying to define a macro for writing empty nodes in a binary tree using tikz-qtree. Referring to the code below, I want the string \missing in my code to be replaced by \edge[draw=none]; {} as-is (just like if I simply did a find and replace in my code).

Is this possible and how can it be done? I don't want to paste \edge[draw=none]; {} every time there is an empty node in my binary tree.

\documentclass{article}
\usepackage{tikz}
\usepackage{tikz-qtree}


\newcommand{\missing}{ \edge[draw=none]; {} }
%intended usage inside tikzpicture enviornment: 
%\Tree  [.3  1
%               \missing ]
%To producce the same result as code below but
%it gave me an error:
%! Undefined control sequence.
%\missing -> \edge 
%                  [draw=none]; {} 

\begin{document}

\begin{tikzpicture}
\Tree  [.3  1
               \edge[draw=none]; {} ]
\end{tikzpicture}

\end{document}
Paulo Cereda
  • 44,220
  • Welcome to TeX.sx! A tip: You can use backticks \`` to [mark your inline code](http://meta.tex.stackexchange.com/questions/863/how-do-i-mark-inline-code) as I did in my edit.:)` – Paulo Cereda Jun 07 '12 at 21:35
  • Unfortunately \edge is not a real command, but a sentinel; if there is, then tikz-qtree is able to do its business. But you can't hide it in a macro. – egreg Jun 07 '12 at 22:54

2 Answers2

19

You need to encourage \missing to expand at the right time:

\documentclass{article}
\usepackage{tikz}
\usepackage{tikz-qtree}
\makeatletter

\let\old@@children\@@children
\def\@@children{\futurelet\my@next\my@@children}
\def\my@@children{%
\ifx\my@next\missing\else
\expandafter\@gobble
\fi
\expandafter\old@@children}

\makeatother

\newcommand{\missing}{ \edge[draw=none]; {} }
%intended usage inside tikzpicture enviornment: 
%\Tree  [.3  1
%               \missing ]
%To producce the same result as code below but
%it gave me an error:
%! Undefined control sequence.
%\missing -> \edge 
%                  [draw=none]; {} 

\begin{document}

\begin{tikzpicture}

\Tree  [.3  1 \missing ]
\end{tikzpicture}

\end{document}
David Carlisle
  • 757,742
5

If you are drawing trees, I urge you to look at forest which is extremely powerful and uses a similar syntax to tikz-qtree/qtree. It also has a built in style for missing nodes:

\documentclass[tikz]{standalone}
\usepackage{forest}

\begin{document}

  \begin{forest}
    [3
      [1
      ]
      [,phantom
      ]
    ]
  \end{forest}

 \end{document}

forest tree with phantom node

If you want to just pass a missing to the relevant node and have the phantom constructed, you can do something like this, which will have the same output as the code above:

\documentclass[tikz,multi,varwidth]{standalone}
\usepackage{forest}

\begin{document}

  \forestset{
    missing/.style={
      before typesetting nodes={
        append={[, phantom]},
      },
    },
  }
  \begin{forest}
    [3, missing
      [1
      ]
    ]
  \end{forest}

 \end{document}

This can be used for non-binary trees where nodes may have more than 2 children. If you might sometimes want to add your missing node in the middle of a node's children in such a tree, you can adapt missing to take an argument equal to the number of the children occurring before the missing node.

For example:

\documentclass[tikz,multi,varwidth]{standalone}
\usepackage{forest}

\begin{document}

  \forestset{
    missing/.style={
      for children={
        if n=#1{
          before typesetting nodes={
            insert after={[, phantom]},
          },
        }{},
      },
    },
  }
  \begin{forest}
    [3, missing=3
      [1
      ]
      [2
      ]
      [3
      ]
      [4
      ]
    ]
  \end{forest}

 \end{document}

more elaborate missing

Something slightly more complex is needed if you might want the first child to be missing i.e. if missing=0 is a possibility:

\documentclass[tikz,multi,varwidth]{standalone}
\usepackage{forest}

\begin{document}

  \forestset{
    missing/.style={
      if={equal(#1,0)}{
        before typesetting nodes={
          prepend={[, phantom]},
        },
      }{
        for children={
          if n=#1{
            before typesetting nodes={
              insert after={[, phantom]},
            },
          }{},
        },
      },
    },
  }
  \begin{forest}
    [0
      [1
      ]
      [2, missing=0
        [2
        ]
        [3
        ]
      ]
      [3, missing=1
        [1
        ]
        [3
        ]
      ]
      [4
      ]
    ]
  \end{forest}

 \end{document}

more elaborate still

This might also be useful in binary trees since you can use 0 for left child missing and 1 for right child missing:

\documentclass[tikz,multi,varwidth]{standalone}
\usepackage{forest}

\begin{document}

  \forestset{
    missing/.style={
      if={equal(#1,0)}{
        before typesetting nodes={
          prepend={[, phantom]},
        },
      }{
        for children={
          if n=#1{
            before typesetting nodes={
              insert after={[, phantom]},
            },
          }{},
        },
      },
    },
  }
  \begin{forest}
    [0
      [1, missing=1
        [1
        ]
      ]
      [2, missing=0
        [2
        ]
      ]
    ]
  \end{forest}

 \end{document}

binary missings

cfr
  • 198,882