4

I am trying to use PGF keys in TikZ with a relatively complex key tree. (Complex by my standards, that is - I'm sure it isn't that complicated in the scheme of things.)

What I hoped to do is to define a command to do following:

  • set keys which are descendants of a particular path in the key tree;
  • save all remaining keys to a macro;
  • do a bunch of other stuff (calculations, processing, setting up);
  • typeset a node using various bits of the processed information;
  • tack on the macro to the node options so that, for example, generic TikZ keys get applied.

Not only can I not get this to work, I can't figure out any logic behind what works and what doesn't. At one point, my MWE wouldn't compile at all while my original document merely failed to produce the desired output.

In my actual document, none of the options I pass seem to have any effect, but I'm hoping that the MWE is getting at the same problem or, at least, one of the same problems.

Here's my current MWE:

\documentclass{article}
\usepackage{tikz}
\begin{document}
\def\mymammals{}
\tikzset{
  mammals/.code={
    \tikzset{
      /pgf/key filters/is descendant of/.install key filter=/animals/mammals/,
      /pgf/key filter handlers/append filtered to/.install key filter handler=\mymammals,
      /animals/mammals/.cd,%
      #1
    }
  },
  /animals/.search also={/tikz},
  /animals/mammals/.search also={/animals,/tikz},
  /animals/mammals/.cd,
  elephant/.store in=\elephant,
  /animals/size/.style={},
}
\newcommand\mammals[1]{%
  \def\mymammals{}%
  \tikzset{mammals={#1}}%
  \node (\elephant) [circle, minimum size=5mm, draw=red, text=red] at (0,0) {x};
  \node (another \elephant) [/animals/size, \mymammals] at (\elephant) {\elephant};
}

\begin{tikzpicture}
  \mammals{
      elephant=Edward,
      text=blue,
      draw,
      minimum width=50mm,
      xshift=-10mm,
      yshift=-20mm
  }
\end{tikzpicture}

\end{document}

What I would like this to do is to produce a red circle containing a red 'x' and, 10mm to the left and 20mm below, a 50mm wide box containing the name 'Edward' in blue with the borders of the node drawn. (Not sure which colour I want here - but let's say black or red or blue would be a start!)

That is, I hope to get this:

dream

However, I get this:

reality

Now I fully accept that I don't know what I'm doing. So I am not surprised this doesn't work. That much I expect.

But why is it partially working? Why is Edward in blue, but the node is not drawn and the shifts are not done?

I'm aware that /animals/size is playing a crucial role here, but I'm not clear why. It shouldn't be switching the default path and, if it was, I should get errors. And since, in my minimised example, this is a style which does nothing at all, it seems bizarre that it should have such partial effects.

This makes me think that I should not be going about this in this way at all, but I can't figure out how I should be doing it if I don't want to put keys into families just in order to solve this problem. If I could say 'All keys which are descendants of ... go in family ...', that would be one thing, but I get the impression that the family concept is supposed to be for categories which are orthogonal to paths in the tree hierarchy.

That is, I have no idea what is going on and the manual is not helping at all. Please can I have a hint?

EDIT

The following appears to work but I'm not sure how safe or sane it is. Nor am I entirely sure why it works.

\documentclass{article}
\usepackage{tikz}
\begin{document}

\tikzset{
  mammals/.code={
    \def\mysaved{}%
    \tikzset{
      /pgf/key filters/defined/.install key filter,
      /pgf/key filter handlers/append filtered to/.install key filter handler=\mysaved,
    }%
    \pgfkeysfiltered{/animals/mammals/.cd,#1}%
    \tikzset{
      /animals/mysaved/.estyle={\mysaved},
    }
  },
  /animals/.search also={/tikz},
  /animals/mammals/.search also={/animals,/tikz},
  /animals/mammals/.cd,
  elephant/.store in=\elephant,
}
\newcommand\mammals[1]{%
  \tikzset{mammals={elephant={??},#1}}%
  \node (\elephant) [circle, minimum size=5mm, draw=red, text=red] at (0,0) {x};
  \node (another \elephant) [/animals/mysaved] at (\elephant) {\elephant};
}

\begin{tikzpicture}
  \mammals{
      elephant=Edward,
      text=blue,
      draw,
      minimum width=50mm,
      xshift=-10mm,
      yshift=-20mm
  }
\end{tikzpicture}

\end{document}
  • A quick test showed that \mymammals is still empty. What were you expecting to be stored there and why? – John Kormylo Oct 14 '15 at 13:44
  • You are obviously trying to teach yourself how to use pgfkeys. Why don't you start simple then add complexity. For example, when you create a new key you should always use /.initial= even if it is never used. – John Kormylo Oct 14 '15 at 13:58
  • @JohnKormylo I'm sure it is simple for you. However, it is incredibly obscure to me. What does the manual mean when it says that /my key will be 'promoted' to... ? I don't understand the idea of promotion here. Moreover, as far as I could tell, .initial only applies to certain kinds of keys. And it has never been obvious to me what it is meant to do. Is there any reason to use .initial in addition to ensuring that a key is set to some value? And why does 'Edward' get printed in blue? This is not the first time I've used PGF keys even if it looks that way. But I admit I don't get it. – cfr Oct 14 '15 at 14:34
  • I ask about .initial because I take it you mean I should have elephant/.initial but that seems superfluous since my real example has something like \tikzset={mammals={elephant={??},#1} in \mammals to ensure that it is always (re)set. Or else I have things like key/.store in=\mykey followed by key=placeholder. Should I have key/.initial=something as well? If so, why? Certainly the manual does not make this at all clear. – cfr Oct 14 '15 at 14:59
  • The other way to learn is to look at the TikZ source code and see how it uses pgfkeys. And yes, even when I use /.default={something} I CREATE the key using /.initial={}. There are some exceptions, like /.is family. – John Kormylo Oct 14 '15 at 21:44

Your Answer

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

Browse other questions tagged or ask your own question.