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 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

enter image description here

share|improve this question
1  
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
1  
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}$ –  cgnieder May 27 '13 at 15:47
3  
@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
1  
The specific problem is that nodes is expanded, not label. –  Ryan Reich May 27 '13 at 16:20
1  
@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
show 11 more comments

2 Answers

up vote 4 down vote accepted

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}
share|improve this answer
    
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
add comment

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':
  .link=color/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.

share|improve this answer
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.