# TikZ: matrix in a matrix gives “missing $” The following TikZ code compiles and renders as expected: \matrix[struct] { \node[varname] (age) {age}; & \node[vartype] {int*}; \\ \node[varname] {height}; & \node[vartype] {float}; \\ \node[varname] {weight}; & \node[vartype] {float}; \\ };  The following does not: \documentclass[tikz,border=10pt,a4paper]{standalone} \usetikzlibrary{arrows,intersections,shapes,backgrounds,scopes,positioning,fit,matrix} %% Language and font encodings \usepackage[english]{babel} \begin{document} \tikzset{varname/.style={rectangle,thin,inner sep=0.3ex,font=\ttfamily,text height=1.5ex,text depth=0.35ex}} \tikzset{vartype/.style={rectangle,text=red,thin,inner sep=0.3ex,font=\ttfamily,text height=1.5ex,text depth=0.35ex}} \tikzset{struct/.style={draw,matrix of nodes,column 1/.style={anchor=base west},column 2/.style={anchor=base west}}} \begin{tikzpicture} \matrix[struct] (person) { \node[varname] {name}; & \node[vartype] {const char*}; \\ \node[varname] {attributes}; & \matrix[struct] (foo) { \node[varname] (age) {age}; & \node[vartype] {int*}; & \\ \node[varname] {height}; & \node[vartype] {float}; & \\ \node[varname] {weight}; & \node[vartype] {float}; & \\ }; \\ \node[varname] {next}; & TODO & \\ }; \end{tikzpicture} \end{document}  Missing$ inserted.

Why not? How to I get a matrix-in-a-matrix?

The objective is to represent data types and structures hierarchically. If a data structure Primary contains another data structure Secondary, then I need to be able to include/invoke the code which draws Secondary inside the code which draws Primary. I need to be able to uniquely name nodes within any given structure, so that I can attach arbitrary decorations to them. ASCII art:

PRIMARY----------------------+
| basic_field:   int         |
| complex_field: SECONDARY--+|
|                | foo: int ||    ______
|                | bar: int<======|note|
|                | baz: int ||    ^^^^^^
|                -----------+|
| basic_field_2: int         |
+----------------------------+

• People don't like to get source from external sources that might not be available later on. Place the code here instead. It is short enough – daleif Mar 8 '17 at 12:35
• BTW: several constructions does not like blank lines, so try removing that blank line before the inner matrix. Removing that blank line will give you the answer. BTW2: what even use a matrix for this? – daleif Mar 8 '17 at 12:37
• Edited, thanks for the advice. What would you use instead of a matrix? I tried with just nodes but had to write a lot of [left=of blah] and that was a lot of typing, requiring me to name all the nodes. – spraff Mar 8 '17 at 12:57
• Can you explain what you actually want to achieve in the end? Is it just about arranging some words in a grid-fashion, or do you also want to draw lines connecting the entries? – gernot Mar 8 '17 at 13:10
• I'm with gernot, explian better what exactly it is you want, then we'll see that we can come up with – daleif Mar 8 '17 at 13:30

A variation on Segletes' solution:

Note: (foo) and (age) will not be defined in the final tikzpicture.

\documentclass[border=10pt]{standalone}

\usepackage{tikz}
\usetikzlibrary{arrows,intersections,shapes,backgrounds,scopes,positioning,fit,matrix}

%% Language and font encodings
\usepackage[english]{babel}% Really?

\newsavebox{\tempbox}

\begin{document}

\tikzset{varname/.style={rectangle,thin,inner sep=0.3ex,font=\ttfamily,text height=1.5ex,text depth=0.35ex}}
\tikzset{vartype/.style={rectangle,text=red,thin,inner sep=0.3ex,font=\ttfamily,text height=1.5ex,text depth=0.35ex}}
\tikzset{struct/.style={draw,matrix of nodes,column 1/.style={anchor=base west},column 2/.style={anchor=base west}}}

\setbox\tempbox=\hbox{\begin{tikzpicture}[baseline=(age.text)]
\matrix[struct] (foo)
{
\node[varname] (age) {age}; & \node[vartype] {int*}; & \\
\node[varname] {height}; & \node[vartype] {float}; & \\
\node[varname] {weight}; & \node[vartype] {float}; & \\
};
\end{tikzpicture}}%

\begin{tikzpicture}
\matrix[struct] (person)
{
\node[varname] {name}; & \node[vartype] {const char*}; \\
\node[varname] {attributes}; & \node{\usebox{\tempbox}}; \\
\node[varname] {next}; & TODO  \\
};
\end{tikzpicture}

\end{document}


• A definite improvement. – Steven B. Segletes Mar 8 '17 at 15:12
• Thank you for this solution, although it doesn't allow me to decorate the nodes properly (see the ASCII art in my original question, and this followup question.) – spraff Mar 8 '17 at 16:35
• The fix is to add the option remember picture to both tikzpicture environments. – spraff Mar 9 '17 at 11:34

This is a bit ugly, because I din't know that standalone builds each tikzpicture in its own page (hat tip to John K in comment). Thus, there exists a standalone border around the outside of the inner struct box. Because of it, I have to resort to \\[-10pt] to eliminate the vertical border around the inner box and \hspace{-10pt} to eliminate the horizontal border. I give an ADDENDUM below showing how that whole issue disappears when not using standalone.

Even if that is fixed, it is still a bit ugly, as I must build the inner box in a separate \vbox and save that, to be regurgitated within the outer box.

\documentclass[tikz,border=10pt,a4paper]{standalone}
\usetikzlibrary{arrows,intersections,shapes,backgrounds,scopes,positioning,fit,matrix}
%% Language and font encodings
\usepackage[english]{babel}
\usepackage{stackengine}
\newcommand\insertmatrix[1]{%
\hspace{-10pt}%
\belowbaseline[-\dimexpr\baselineskip+\ht\strutbox\relax]{#1}%
\hspace{-10pt}%
}
\begin{document}

\tikzset{varname/.style={rectangle,thin,inner sep=0.3ex,font=\ttfamily,text height=1.5ex,text depth=0.35ex}}
\tikzset{vartype/.style={rectangle,text=red,thin,inner sep=0.3ex,font=\ttfamily,text height=1.5ex,text depth=0.35ex}}
\tikzset{struct/.style={draw,matrix of nodes,column 1/.style={anchor=base west},column 2/.style={anchor=base west}}}

\setbox0=\vbox{\begin{tikzpicture}
\matrix[struct] (foo)
{
\node[varname] (age) {age}; & \node[vartype] {int*}; & \\
\node[varname] {height}; & \node[vartype] {float}; & \\
\node[varname] {weight}; & \node[vartype] {float}; & \\
};
\end{tikzpicture}}
\savestack\mycomplex{\box0}
\begin{tikzpicture}
\matrix[struct] (person)
{
\node[varname] {name}; & \node[vartype] {const char*}; \\[-10pt]
\node[varname] {attributes}; & \insertmatrix{\mycomplex}
\\[-10pt]
\node[varname] {next}; & TODO  \\
\node[varname] {afternext}; & MORE TODO  \\
};
\end{tikzpicture}

\end{document}


Thanks to John for pointing out the issue being with standalone, not tikz. If I perform the task in article class, all those 10pt corrections are not needed, and the \vbox can be put into an \hbox.

\documentclass[tikz,border=10pt,a4paper]{article}
\usepackage{tikz}
\usetikzlibrary{arrows,intersections,shapes,backgrounds,scopes,positioning,fit,matrix}
%% Language and font encodings
\usepackage[english]{babel}
\usepackage{stackengine}
\newcommand\insertmatrix[1]{%
\belowbaseline[-\ht\strutbox]{#1}%
}
\begin{document}

\tikzset{varname/.style={rectangle,thin,inner sep=0.3ex,font=\ttfamily,text height=1.5ex,text depth=0.35ex}}
\tikzset{vartype/.style={rectangle,text=red,thin,inner sep=0.3ex,font=\ttfamily,text height=1.5ex,text depth=0.35ex}}
\tikzset{struct/.style={draw,matrix of nodes,column 1/.style={anchor=base west},column 2/.style={anchor=base west}}}

\setbox0=\hbox{\begin{tikzpicture}
\matrix[struct,ampersand replacement=\&] (foo)
{
\node[varname] (age) {age}; \& \node[vartype] {int*}; \& \\
\node[varname] {height}; \& \node[vartype] {float}; \& \\
\node[varname] {weight}; \& \node[vartype] {float}; \& \\
};
\end{tikzpicture}}
\savestack\mycomplex{\box0}
\begin{tikzpicture}
\matrix[struct] (person)
{
\node[varname] {name}; & \node[vartype] {const char*}; \\
\node[varname] {attributes}; & \insertmatrix{\mycomplex}
\\
\node[varname] {next}; & TODO  \\
\node[varname] {afternext}; & MORE TODO  \\
};
\end{tikzpicture}

\end{document}

• \setbox0=\hbox{} also works, while \savebox doesn't. – John Kormylo Mar 8 '17 at 14:59
• @JohnKormylo I could not get it to work with \hbox. – Steven B. Segletes Mar 8 '17 at 15:01
• The [tikz] option to standalone puts every tikzpicture on a new page. – John Kormylo Mar 8 '17 at 15:17
• @JohnKormylo Thanks. That explains a lot, and I have edited my answer to reflect that new information. – Steven B. Segletes Mar 8 '17 at 15:26

I suggest to use plain LaTeX for the grid-like arrangements and tikz for annotations. Instead of \fbox you can use fancier methods of drawing nice boxes.

\documentclass{article}
\usepackage{tikz}
\newcommand\vartype[1]{\textcolor{red}{\ttfamily#1}}
\newcommand\varname[1]{{\ttfamily#1}}
\newcommand\struct[1]%
{\fbox
{\begin{tabular}[t]{@{}ll@{}}
#1
\end{tabular}%
}%
}
\newcommand\tikznode[2]%
{\tikz[remember picture,baseline=(#1.base)]\node[inner sep=0pt] (#1) {#2};}

\begin{document}
\struct
{\varname{name}       & \vartype{const char*} \\
\varname{attributes}
& \struct
{\varname{age}    & \vartype{int*}  \\
\varname{height} & \tikznode{heighttype}{\vartype{floatp}} \\
\varname{weight} & \vartype{float}
} \\[7ex]
\varname{next}       & TODO
}
\begin{tikzpicture}[remember picture,overlay]
\draw[stealth-,shorten <=2pt] (heighttype) -- +(1,1) node[right] {important!};
\end{tikzpicture}
\end{document}