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.

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

enter image description here

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}
share|improve this question
    
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
1  
I've changed them to what seems to be an accurate description of the issue. –  Ryan Reich Jun 26 '12 at 6:10
add comment

1 Answer

up vote 6 down vote accepted

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
       %%% ADDED \expandonce\c
       \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}%
}
share|improve this answer
    
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
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.