10

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

16
  • 1
    You can add \noexpand before the \sqrt, but I guess that's not the solution you're looking for.
    – Jake
    May 27, 2013 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, 2013 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. May 27, 2013 at 15:51
  • 1
    The specific problem is that nodes is expanded, not label.
    – Ryan Reich
    May 27, 2013 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! May 27, 2013 at 17:19

2 Answers 2

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}
3
  • What are \i, a, b doing in your scheme? Also, the key execute style seems redundant.
    – Ahmed Musa
    May 27, 2013 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, 2013 at 4:07
  • @RyanReich: What of execute macro/.expand once=#1?
    – Ahmed Musa
    May 29, 2013 at 17:43
3

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.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .