9

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

  • 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}$ – clemens 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
4

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:
  % https://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
2

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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.