# How can I inhibit expansion through several layers of \edef?

I'm using a macro I've defined based on some suggestions here to automate the creation of tables.

For example something like

\newcommand{\clearrows}{\let\matrixcontent\empty}
\newcommand{\actionsrow}[3]{%
\foreach \i in #3 {%
\pgfmathparse{#1[\i-1]}
\let\c\pgfmathresult
\pgfmathparse{#2[\i-1]}
\let\s\pgfmathresult
\begingroup\edef\x{\endgroup
\noexpand\gappto\noexpand\matrixcontent{\noexpand\node[\s]{\c}; \&}}\x
}%
\gappto\matrixcontent{\\}%
}


lets me easily create the tables I need, with a few lines of code. For example,

\newcommand{\rowhv}[1]{
\actionsrow{{"$e$","$h$","$v$","$hv$"}}{{{"fill=gray!3"},{"fill=gray!33"},{"fill=gray!67"},{"fill=gray!100"}}}{#1} }
\clearrows
\rowhv{{1,2,3,4}} \rowhv{{2,1,4,3}} \rowhv{{3,4,1,2}} \rowhv{{4,3,2,1}}

\begin{tikzpicture}
\matrix[ampersand replacement=\&,nodes={minimum size=7mm}]{\matrixcontent};
\end{tikzpicture}


produces

which may not seem like much of an accomplishment, but I need to build quite large tables, and a lot of them, so these macros are essential.

I need to be able to put arbitrary content in the cells, ranging from arbitrary formatting (e.g., \textsf{..}) to imported images (using, for example, \includegraphics) or other macros I define to draw node contents. But the code above only works for cell contents that are plain text. If I supply anything other other than plain text among the items in the first argument to \actionsrow, which is used for \c in the loop there, I get an error,

Argument of \reserved@a has an extra }.

even though such content is perfectly valid for nodes. I suspect there's something going on with the way my (pilfered) macro is parsing \c, but I don't even know where to begin track that down.

How can I modify my \actionsrow macro so that I can specify arbitrary LaTeX as contents for my nodes?

\documentclass[]{article}

\usepackage{etoolbox}
\usepackage{tikz}
\usetikzlibrary{matrix}

\begin{document}

% See -- http://tex.stackexchange.com/a/47649/7844
\newcommand{\clearrows}{\let\matrixcontent\empty}
\newcommand{\actionsrow}[3]{%
\foreach \i in #3 {%
\pgfmathparse{#1[\i-1]} % See -- http://tex.stackexchange.com/a/56838/7844; note \let vs \def
\let\c\pgfmathresult
\pgfmathparse{#2[\i-1]}
\let\s\pgfmathresult
\begingroup\edef\x{\endgroup
\noexpand\gappto\noexpand\matrixcontent{\noexpand\node[\s]{\c}; \&}}\x
}%
\gappto\matrixcontent{\\}%
}

% This works fine
\newcommand{\rowhv}[1]{
\actionsrow{{"$e$","$h$","$v$","$hv$"}}{{{"fill=gray!3"},{"fill=gray!33"},{"fill=gray!67"},{"fill=gray!100"}}}{#1} }
\clearrows
\rowhv{{1,2,3,4}} \rowhv{{2,1,4,3}} \rowhv{{3,4,1,2}} \rowhv{{4,3,2,1}}

\begin{center}
\begin{tikzpicture}
\matrix[ampersand replacement=\&,nodes={minimum size=7mm}]{\matrixcontent};
\end{tikzpicture}
\end{center}

% Here, arbitrary specifications work for the nodes, if done manually
\begin{center}
\begin{tikzpicture}
\matrix [nodes={minimum size=7mm}]
{
\node[fill=gray!3]{\texttt{e}}; & \node[fill=gray!33]{\color{red}$h$}; & \node[fill=gray!67]{$v$}; & \node[fill=gray!100]{$hv$}; \\
\node[fill=gray!33]{\color{red}$h$}; & \node[fill=gray!3]{\texttt{e}}; & \node[fill=gray!100]{$hv$}; & \node[fill=gray!67]{$v$}; \\
\node[fill=gray!67]{$v$}; & \node[fill=gray!100]{$hv$}; & \node[fill=gray!3]{\texttt{e}}; & \node[fill=gray!33]{\color{red}$h$}; \\
\node[fill=gray!100]{$hv$}; & \node[fill=gray!67]{$v$}; & \node[fill=gray!33]{\color{red}$h$}; & \node[fill=gray!3]{\texttt{e}}; \\
};
\end{tikzpicture}
\end{center}

% But this fails
\renewcommand{\rowhv}[1]{
\actionsrow{{"\texttt{e}","\color{red}$h$","$v$","$hv$"}}{{{"fill=gray!3"},{"fill=gray!33"},{"fill=gray!67"},{"fill=gray!100"}}}{#1} }
\clearrows
\rowhv{{1,2,3,4}} \rowhv{{2,1,4,3}} \rowhv{{3,4,1,2}} \rowhv{{4,3,2,1}}

\begin{center}
\begin{tikzpicture}
\matrix[ampersand replacement=\&,nodes={minimum size=7mm}]{\matrixcontent};
\end{tikzpicture}
\end{center}

￼\end{document}

-
I'd appreciate help titling and tagging this question: I may not have the source of my problem properly identified. –  raxacoricofallapatorius Jun 26 '12 at 3:50
I've changed them to what seems to be an accurate description of the issue. –  Ryan Reich Jun 26 '12 at 6:10

You have two problems, both with \edef. The second one is literally with your \edef, as any macro inside #1 that finds its way into \c will be expanded into \x and create chaos. The first one is with \pgfmathparse, as according to the manual, everything in a math expression is fully expanded, and therefore, you will require extra protection for things that should not be expanded. I see two ways around this:

1. Put \unexpanded around every item in array #1 manually, and also put \expandonce in front of \c inside that \edef (so it is expanded but its contents are not). This is a pain but will fix the problem.

2. Do a preliminary loop with \foreach to put in those \unexpandeds before continuing with the current body of \actionsrow. Since it will be a pain to get the double quotes to interact well with this, I suggest you make the syntax for its first argument {$a$, $\mathbf{b}$, \includegraphics{c.pdf}, ...}, without the quotes, and have \foreach add both the \unexpanded and the quotes. Also, don't forget \expandonce\c in the \edef, as before.

Here is how I implemented option 2:

\newcommand{\actionsrow}[3]{%
%%%
% NEW STUFF
%%%
\let\comma=\empty
\let\b=\empty
\foreach \a in {#1} {%
\xappto\b{\comma"\noexpand\unexpanded{\expandonce\a}"}%
\gdef\comma{,}%
}%
\foreach \i in #3 {%
%%% CHANGED #1 -> \b
\pgfmathparse{{\b}[\i-1]}%
\let\c\pgfmathresult
\pgfmathparse{#2[\i-1]}%
\let\s\pgfmathresult
\begingroup\edef\x{\endgroup
\noexpand\gappto\noexpand\matrixcontent{\noexpand\node[\s]{\expandonce\c}; \&}}\x
}%
\gappto\matrixcontent{\\}%
}

\newcommand{\rowhv}[1]{
\actionsrow
%%% NEW SYNTAX: first arg is a pure CSV list
{$\mathbf{e}$,$h$,$v$,$hv$}
{{{"fill=gray!3"},{"fill=gray!33"},{"fill=gray!67"},{"fill=gray!100"}}}
{#1}%
}

-
Thanks, this does a great job. I still have some issues with certian arguments (e.g. \color{..}: "Undefined color 'r'"). It also looks like I need to do some reading on how expansion works. –  raxacoricofallapatorius Jun 26 '12 at 14:36
What problems are you having with color? If I put \color{red} into the $h$, for example, it works just fine. –  Ryan Reich Jun 26 '12 at 16:05
Interesting: it works inside the $..$, but not outside: \color{red}h and \color{red}$h$ fail, but \color{red}$h$ works. –  raxacoricofallapatorius Jun 26 '12 at 19:14
I also don't seem to be able to provide any arguments that use the scope environment (e.g. many figures I'd like do draw and place in the cells). –  raxacoricofallapatorius Jun 26 '12 at 19:42
This seems to be a problem (likely a bug) with the way pgfmath treats arrays. Try \pgfmathparse{{"{red}a", "b"}[0]}\pgfmathresult and cringe at the result. It actually catches the "nested array" {red}; apparently, no braces are safe in array elements. –  Ryan Reich Jun 26 '12 at 23:10