# Expansion problems with pgfkeys

I'm using pgfkeys, and a fairly adventurous syntax in which the values for some keys contain additional key/value pairs. (For instance, the value of the nodes key is a list of pairs, and the second component of each pair is a key-value list.)

I get a compilation error whenever I put anything too fancy into the label key. The code below works fine as-is, but if I replace 2+2 with 2+\sqrt{2}, it breaks. I think it's a macro-expansion problem. How can I arrange it that the contents of the label key does not get expanded until it needs to be?

## Code

\documentclass{article}
\usepackage{tikz}

\makeatletter

\pgfkeys{/wickerson/.cd,
% The following two lines are from:
% http://tex.stackexchange.com/q/85637/86
execute style/.style = {#1},
execute macro/.style = {execute style/.expand once=#1},
left/.code=            {\xdef\wickerson@left{#1}},
top/.code=             {\xdef\wickerson@top{#1}},
label/.code=           {\gdef\wickerson@label{#1}},
nodes/.code=           {\xdef\wickerson@nodes{#1}},
colour/.code=          {\xdef\wickerson@colour{#1}},
}

\newcommand\myDiagram[1][]{%
\pgfkeys{/wickerson/.cd,colour=black,nodes={},#1}
\node[text=\wickerson@colour] at (0,0) {My Diagram...};
\foreach \i/\values in \wickerson@nodes {
\pgfkeys{/wickerson/.cd,left=0,top=0,label={},%
execute macro=\values}
\node[shape=circle,draw=black]
at (\wickerson@left, \wickerson@top)
{\wickerson@label};
}
}

\makeatother

\begin{document}

\begin{tikzpicture}[x=1mm,y=-1mm]
\myDiagram[%
colour=red, %
nodes={%
a/{left=0,top=10,label={$2+2$}}, %
b/{left=15,top=10,label={$\log 4$}}%
}%
]
\end{tikzpicture}

\end{document}


## Output

-
You can add \noexpand before the \sqrt, but I guess that's not the solution you're looking for. – Jake May 27 '13 at 12:48
In the MWE you neither need global assignments nor expanded ones. In each of the keys a simple \def should suffice. Then there also won't be an error with $2+\srqt{2}$ – clemens May 27 '13 at 15:47
@cgnieder This is probably an answer. Also, with eTeX, \edef\foo{\unexpanded{#1}} is slightly better than \def\foo{#1}, because it will correctly escape macro parameter characters # that are given inside the key, for even wilder labels. – Bruno Le Floch May 27 '13 at 15:51
The specific problem is that nodes is expanded, not label. – Ryan Reich May 27 '13 at 16:20
@percusse Oh. Hm. I thought the whole point of the directory structure in pgfkeys was so that you could use existing names like label for your keys! – John Wickerson May 27 '13 at 17:19

Just to confirm that cgnieder's comment and Ryan Reich's explanation were right on target. I have managed to fix my code and understand the problem too. Thanks folks!

\documentclass{article}
\usepackage{tikz}

\makeatletter

\pgfkeys{/wickerson/.cd,
% The following two lines are from:
% http://tex.stackexchange.com/q/85637/86
execute style/.style = {#1},
execute macro/.style = {execute style/.expand once=#1},
left/.code=            {\def\wickerson@left{#1}},
top/.code=             {\def\wickerson@top{#1}},
label/.code=           {\def\wickerson@label{#1}},
nodes/.code=           {\def\wickerson@nodes{#1}},
colour/.code=          {\def\wickerson@colour{#1}},
}

\newcommand\myDiagram[1][]{%
\pgfkeys{/wickerson/.cd,colour=black,nodes={},#1}
\node[text=\wickerson@colour] at (0,0) {My Diagram...};
\foreach \i/\values in \wickerson@nodes {
\pgfkeys{/wickerson/.cd,left=0,top=0,label={},%
execute macro=\values}
\node[shape=circle,draw=black]
at (\wickerson@left, \wickerson@top)
{\wickerson@label};
}
}

\makeatother

\begin{document}

\begin{tikzpicture}[x=1mm,y=-1mm]
\myDiagram[%
colour=red, %
nodes={%
a/{left=0,top=10,label={$\sqrt{2}+2$}}, %
b/{left=15,top=10,label={$\log 4$}}%
}%
]
\end{tikzpicture}

\end{document}

-
What are \i, a, b doing in your scheme? Also, the key execute style seems redundant. – Ahmed Musa May 27 '13 at 23:22
@Ahmed if I may answer for John: I expect that a and b (as stored in \i) are intended to be used as node names eventually. As for execute style, it is necessary to have a key to "hang" the .expand once handler on, since the result of a handler is always passed up to the parent key. – Ryan Reich May 28 '13 at 4:07
@RyanReich: What of execute macro/.expand once=#1? – Ahmed Musa May 29 '13 at 17:43

Here is a solution with skeyval package.

\documentclass{article}
\usepackage{tikz}
\usepackage{skeyval}[2013/05/01]
\makeatletter
\directkeys{%
.family=wickerson,
.holder prefix=wic@,
.define keys={%
.cmd/left/0,
.cmd/top/0,
.cmd/label//,
.cmd/colour/black,
.zcmd/title colour/black,
.ord/nodes//
\skvifblankTF{#1}{}{%
\node[text=\wic@titlecolour] at (0,0) {My Diagram ...};
\edef\tempa{\unexpanded{#1}}%
\skvstripouterbraces{1}\tempa
\newforeach [expand list once] \x in \tempa {%
% Use the parameter rep of \x:
\skvsetkeys{wickerson}{##1}%
\node[shape=circle,draw=\wic@colour] at (\wic@left,\wic@top){\wic@label};
}%
},
},
% Allow 'color' to be a clone of 'colour':
}
\newcommand\myDiagram[1][]{%
\directkeys{%
.family=wickerson,
.set keys={nodes,left,top,label,colour,title colour},
.set keys={#1}
}%
}
\makeatother
\begin{document}
\begin{tikzpicture}[x=1mm,y=-1mm]
\myDiagram[%
title colour=green,
nodes={
{color=red,left=0,top=10,label={$\sqrt{2}+2$}},
{color=blue,left=15,top=10,label={$\log 4$}}
}%
]
\end{tikzpicture}
\end{document}


Note: I don't have the jpeg, png, tiff, gif or bmp format of output that this site is insisting on.

-