8

I have macros which take a list of keys as argument and pass this list on to \tikzsets which each use a specific namespace. In the example below macros of this type would be \marmot and \koala. This works all well so far.

Now I'd like to call another macro (let's call it \thing) from within these macros, which again has a \tikzset with a unique namespace.

At the moment I simply pass the complete list of keys to the \thing macro, which results in two possibilities:

  • either it complains about unknown keys, for example if hat,teeth is passed to marmot, \thing only knows hat but not teeth, which is a key for the marmot

  • to workaround I can add /marmot,/koala to .search also, but this gets quite annoying to maintain as soon as there is a large number of different macros which can call \thing

Are there better ways to deal with this quagmire?

\documentclass{article}
\usepackage{tikz}

% things %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\newcommand*{\thing}[1][]{%
    \begin{scope}%
        \tikzset{/thing/.cd,#1}%
        \fill[black] (0,0) rectangle (0.3,0.3);
    \end{scope}%
}

\tikzset{
  /thing/.search also={/tikz,/pgf,
    /marmot,/koala % HERE: I'm looking for a better way than to list all possible namespaces
  },
  /thing/.cd,
  hat/.code = {},
}

% marmot %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\newcommand*{\marmot}[1][]{%
    \begin{scope}%
        \tikzset{/marmot/.cd,#1}%
        \fill[brown] (0.15,-0.3) ellipse (0.3 and 0.5);
    \end{scope}%
    \thing[#1]%
}

\tikzset{
  /marmot/.search also={/tikz,/pgf,/thing},
  /marmot/.cd,
  teeth/.code = {},
}

% koala %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\newcommand*{\koala}[1][]{%
    \begin{scope}%
        \tikzset{/koala/.cd,#1}%
        \fill[gray] (0.15,-0.3) ellipse (0.3 and 0.5);
    \end{scope}%
    \thing[#1]%
}

\tikzset{
  /koala/.search also={/tikz,/pgf,/thing},
  /koala/.cd,
  sleep/.code = {},
}

\begin{document}

\begin{tikzpicture}
\thing[hat]
\end{tikzpicture}

\bigskip

\begin{tikzpicture}
\marmot[teeth]
\end{tikzpicture}

\bigskip

\begin{tikzpicture}
\koala[sleep]
\end{tikzpicture}

\bigskip

\begin{tikzpicture}
\marmot[hat,teeth]
\end{tikzpicture}

\end{document}

Second level of craziness

To make things even more complicated, I also have a macro where I don't know in advance if I end up with a marmot or koala

% tikzling %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\pgfmathdeclarerandomlist{tikzlings}{{\marmot}{\koala}}
\newcommand{\tikzling}[1][]{%
    \tikzset{%
      /thing/.search also={/tikz,/pgf,/marmot,/koala}
    }
    \pgfmathrandomitem{\tikzlingrandom}{tikzlings}%
    \tikzlingrandom[#1]
}

which means that \tikzling[hat,teeth] will cause an error half the time...

In case it would help anybody to see the full code, it is available from https://github.com/samcarter/tikzlings

  • I'm not sure if namespaces is the correct term, if someone knows a better word, please tell. – user36296 Oct 10 '18 at 15:31
  • I'm not clear exactly what the logic you are trying to implement looks like. Do you want inapplicable options to do nothing? In that case, you can set the unknown option handler to be a no-op instead of an error. – Hood Chatham Oct 10 '18 at 17:56
  • It seems to me that if the macro has its own namespace, then the calling macro needs to determine which options are appropriate and pass only those. That is what you would need to do if you were to invoke a macro that was written by someone else. Otherwise, why not just use the same namespace and let the sub macros access it directly rather than passing it in. – Peter Grill Oct 10 '18 at 19:50
  • @HoodChatham That would probably be an easy workaround. Would you happen to have an example how to do this? – user36296 Oct 10 '18 at 20:06
  • @PeterGrill Very good point! I don't see any disadvantages of one single namespace with my MWE. I'll text with the complete project and report back. – user36296 Oct 10 '18 at 20:12
1

Since you only want to avoid the keys that are not in the current namespace, but you don't want to do anything with them in this place, what you can do is just \relax all unknown stuff.

\pgfkeys{/thing/.unknown/.code=\relax}

The keys are going to be called again in the other commands, so their definition will not be lost. The drawback, of course, is that you can not do anything specific with those unknown keys because all will be \relaxed.

This works:

 \documentclass{article}
\usepackage{tikz}

% things %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\newcommand*{\thing}[1][]{%
    \begin{scope}%
        \tikzset{/thing/.cd,#1}%
        \fill[black] (0,0) rectangle (0.3,0.3);
    \end{scope}%
}

\pgfkeys{/thing/.unknown/.code=\relax}

\tikzset{
  %/thing/.search also={/tikz,/pgf,
    %/marmot,/koala % HERE: I'm looking for a better way than to list all possible namespaces
  %},
  /thing/.cd,
  hat/.code = {},
}

% marmot %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\newcommand*{\marmot}[1][]{%
    \begin{scope}%
        \tikzset{/marmot/.cd,#1}%
        \fill[brown] (0.15,-0.3) ellipse (0.3 and 0.5);
    \end{scope}%
    \thing[#1]%
}

\pgfkeys{/marmot/.unknown/.code=\relax}

\tikzset{
  %/marmot/.search also={/tikz,/pgf,/thing},
  /marmot/.cd,
  teeth/.code = {},
}

% koala %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\newcommand*{\koala}[1][]{%
    \begin{scope}%
        \tikzset{/koala/.cd,#1}%
        \fill[gray] (0.15,-0.3) ellipse (0.3 and 0.5);
    \end{scope}%
    \thing[#1]%
}

\pgfkeys{/koala/.unknown/.code=\relax}

\tikzset{
  %/koala/.search also={/tikz,/pgf,/thing},
  /koala/.cd,
  sleep/.code = {},
}

\begin{document}

\begin{tikzpicture}
\thing[hat]
\end{tikzpicture}

\bigskip

\begin{tikzpicture}
\marmot[teeth]
\end{tikzpicture}

\bigskip

\begin{tikzpicture}
\koala[sleep]
\end{tikzpicture}

\bigskip

\begin{tikzpicture}
\marmot[hat,teeth]
\end{tikzpicture}

\end{document}

enter image description here

  • Thanks a lot for your answer! I tested it and it works great! If you don't mind I'll wait a tiny bit longer before I accept it for a totally selfish reason: I hope to get a palindrome number in my reputation soon and if I would accept your answer right know, I would get 2 points which would destroy my chances for the palindrome :) – user36296 Oct 11 '18 at 14:58
  • No problem at all ;-) It is not an elegant solution, so maybe somebody with more knowledge comes with something better. I hope you get your palindrome. – Raoul Kessels Oct 11 '18 at 15:02
  • I forgot to say that .unknown/.code=\relax can be added to the \tikzset itself. – Raoul Kessels Oct 11 '18 at 15:05
  • I think it is an easy approach. And because the \thing macro is primarily designed to be called from within another command, the outer command already throws an error if a totally wrong key is used. So I think this is relativity low risk as one still notice if there is a typo somewhere. – user36296 Oct 11 '18 at 15:08
  • Thanks for your understanding about the delay in accepting your answer - in case it is any consolation: it worked :) i.stack.imgur.com/lqGWB.png – user36296 Oct 11 '18 at 15:59

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.