4

This question tries to expand upon the another both of which aim at providing a "Best" practices for tikz-pics or atleast a couple of how to examples clarifying some of the more advanced trickery that one may employ.

Requirements :

It typically makes sense to have a set of base dimensions for a pic. Allowing the user to alter these dimensions enables them to customize the pic in some small way. This is useful under various circumstances. TikZ collects the options for a pic into the pic actions for commands reading \draw pic[PIC ACTIONS] {...}. It would seem sensible to allow options specified within pic actions to be passed through to a branch in the pgf tree, pick of any relevant keys and pass the remaining keys back up the tree to some other family that knows how to process them.

Code :

This questions takes the cleaner code from @LoopSpace, strips away the calligraphy code to focus upon handling pic actions. I have tried four methods in the code which basically try to pass the keys into the correct branch and if they re not present pass them up the tree. Mostly I'm trying this against the .search also handler.

\documentclass[tikz]{standalone}

\usetikzlibrary{calc,calligraphy}

\makeatletter
\def\inf@key#1{%
  \pgfkeysvalueof{/tikz/infinity dimensions/#1}%
}    
\tikzset{
 % Dimensions
 infinity dimensions/.is family,
 infinity dimensions/width/.initial =1 em,
 infinity dimensions/height/.initial=1 em,
 infinity dimensions/upper target/.initial=0.2,
 infinity dimensions/lower target/.initial=0.8,
 infinity dimensions/.search also={/tikz, /pgf},
 % Method 1
 %infinity dimensions/.style={infinity dimensions/.cd,},
 % Method 2
 %infinity dimensions/.style={infinity dimensions/#1},
 % Method 3
 infinity dimensions/.style={infinity dimensions/.cd,#1},
 % Method 4
 %infinity dimensions/.style={@infinity dimensions/.list={#1}},
 %@infinity dimensions/.style={/tikz/infinity dimensions/#1}
 % Pic/Symbol
 infinity symbol/.pic = {
  % Method 1
  %\draw[infinity dimensions, pic actions] 
  % Method 2
  %\draw[infinity dimensions=pic actions] 
  % Method 3
  \draw[infinity dimensions=pic actions] 
  % Method 4
  %\draw[infinity dimensions={pic actions}] 
     let \p1=(0,0) in 
     (\p1) .. controls (-\inf@key{upper target}*\inf@key{width}, \inf@key{height}) and (-\inf@key{lower target}*\inf@key{width},-\inf@key{height}) .. 
     (\p1) .. controls ( \inf@key{lower target}*\inf@key{width}, \inf@key{height}) and ( \inf@key{upper target}*\inf@key{width},-\inf@key{height}) .. cycle;
 },
}
\makeatother

\begin{document}
\begin{tikzpicture}
\draw pic[double] {infinity symbol};
\end{tikzpicture}
\begin{tikzpicture}
\draw pic[height=2em] {infinity symbol};
\end{tikzpicture}
\end{document}

Problem :

Method(s) 1 and 4 return an error stating that /tikz/height does not exist. Method(s) 2 and 3 return an error stating that /tikz/infinity dimensions/pic actions does not exist. It seems the code either jumps up a level to the /tikz and /pgf roots and fails to recognize something from the /tikz/infinity dimensions branch or it fails to recognize pic actions within the /tikz/infinity dimensions.

Question :

How does one pass the pic actions to some underlying style such that parts of that style may be set and that style options not covered by that style get passed back up to the /tikz and /pgf branches.

The simplest mechanism for this might be the use of the .search also handlers, but my atempts with this seem to fail. Perhaps it is more complex and one really requires key filtering.

Background :

This question implies that pic actions are limited in some way. @Qrrbrbirlbel provides some alternate strategies but I haven't succeeded with any of them.

2
  • I can't give you a detailed answer now, but I think that you might get some guidance by looking at my cobordism package (which is in TeXLive) as that uses pics and there are lots of options to be passed to how the pic is drawn. Commented Jun 20, 2016 at 21:17
  • It seems the tqft/.unknown and tqft/.style are working together somehow. Though your .unknown handler looks rather similar to that in the pgf manual where they explain the .search also handler. I'll take another bash at it in the morning. A possibly related question.
    – Carel
    Commented Jun 21, 2016 at 0:19

2 Answers 2

3

It is a bit misleading to say pic actions are limited. Of course, they are limited, just like everything else. A hammer is limited: it can't boil water.

I think the problem is that you are trying to make them do something they are not designed for and, possibly, trying to use pics for something they weren't designed for. pics are easy to create but, as is usually the case, that convenience has a cost in terms of power and flexibility. You can have the power and flexibility without the convenience, of course, by not using a pic.

This is not the way I usually configure pics because I didn't want to overwrite your configuration simply because I tend to do things differently. But I think the key is that the easiest way to set options flexibly is to pass them as an argument to the particular pic rather than passing them as options to the pic path.

For example,

\documentclass[tikz,border=10pt,multi]{standalone}
\usetikzlibrary{calc}
\makeatletter
\def\inf@key#1{%
  \pgfkeysvalueof{/tikz/infinity dimensions/#1}%
}
\tikzset{
  % Dimensions
  infinity dimensions/.is family,
  infinity dimensions/width/.initial =1 em,
  infinity dimensions/height/.initial=1 em,
  infinity dimensions/upper target/.initial=0.2,
  infinity dimensions/lower target/.initial=0.8,
  infinity dimensions/.search also={/tikz,/pgf},
  infinity setup/.code={%
    \tikzset{%
      infinity dimensions/.cd,
      #1,
      /tikz/.cd,
    }%
  },
  infinity symbol/.pic = {%
    \draw [infinity dimensions/.cd, pic actions, infinity setup=#1]
    let \p1=(0,0) in
    (\p1) .. controls (-\inf@key{upper target}*\inf@key{width}, \inf@key{height}) and (-\inf@key{lower target}*\inf@key{width},-\inf@key{height}) ..
    (\p1) .. controls ( \inf@key{lower target}*\inf@key{width}, \inf@key{height}) and ( \inf@key{upper target}*\inf@key{width},-\inf@key{height}) .. cycle;
  },
}
\makeatother
\begin{document}
\begin{tikzpicture}
  \draw pic [rotate=-45] {infinity symbol={height=2em, line width=2mm, double=blue, draw=green}};
\end{tikzpicture}
\end{document}

lurid infinity

2
  • Limited was perhaps not the correct term, I think wrapped or encapsulated is perhaps better. pic actions seems to be expanded under certain circumstances. I was trying not to deviate from the usual TikZ interface. Using [infinity dimensions/.cd, pic actions] should really apply the pic actions within the infinity dimensions branch, as I understand it, but it seems to fail, perhaps pic actions resets the branch it executes on.
    – Carel
    Commented Jun 21, 2016 at 9:52
  • There was a question on here about creating a house as a pic and it got me curious about the possibilities. If one created a pic that drew a basic house but allowed on to optionally enable parts of the pic by say enabling a door, window or chimney. This would allow one to draw a number of variants of a base symbol which is useful in quite a number of situations. You said you configure your pics differently, would it be possible to post an example ?
    – Carel
    Commented Jun 21, 2016 at 10:07
0

This answer is meant as a compliment to @cfr's one.

Observations:

@cfr's answer is more flexible then he's shown for instance one can readily use the following invocation to draw the symbol

\draw pic [rotate=-45, infinity setup={height=2em, line width=2mm, double=blue, draw=green}] {infinity symbol};

Code :

While playing with the code from @cfr code I stumbled upon an alternate way of implementing the same mechanism that he/she provided posted here. Execution wise it does not appear to add but it cleans up the code a little.

\documentclass[tikz]{standalone}

\usetikzlibrary{calc,calligraphy}

\makeatletter
\def\inf@key#1{%
  \pgfkeysvalueof{/tikz/infinity dimensions/#1}%
}

The initial part reads the same and simply sets up the dimensions.

\tikzset{
 % Dimensions
 infinity dimensions/.is family,
 %infinity dimensions/.search also={/tikz, /pgf},
 infinity dimensions/width/.initial =1 em,
 infinity dimensions/height/.initial=1 em,
 infinity dimensions/upper target/.initial=0.2,
 infinity dimensions/lower target/.initial=0.8,
}

Then we adapt @cfr's code as follows, based upon the other answer. It seems common practice to provide an every KEY and a corresponding KEY that sets it. Supposedly this is done every where within tikz but I haven't confirmed this.

\tikzset{
 every infinity/.style={pic actions, infinity dimensions/.cd},
 infinity/.style={every infinity/.append style={#1}},
}

The use of #1 enables the \draw pic {infinity={...}}; call signature, removing it causes tikz to simply ignore the input. That is one is enforcing the use of \draw pic[infinity={...}] {infinity}; instead. The latter syntax passes the options to every infinity/.style via infinity/.syle, providing an interface similar to @cfr's code.

\tikzset{
 % Pic/Symbol
 infinity symbol/.pic = {
  \path[every infinity, #1]
     let \p1=(0,0) in 
     (\p1) .. controls (-\inf@key{upper target}*\inf@key{width}, \inf@key{height}) and (-\inf@key{lower target}*\inf@key{width},-\inf@key{height}) .. 
     (\p1) .. controls ( \inf@key{lower target}*\inf@key{width}, \inf@key{height}) and ( \inf@key{upper target}*\inf@key{width},-\inf@key{height}) .. cycle;
 },
}
\makeatother

\begin{document}
\begin{tikzpicture}
\draw pic[draw] at (0,-0.5em) {infinity symbol};
\draw pic[draw, double,infinity={lower target=1.5,upper target=0.5}] at (0, 0.5em) {infinity symbol};
\draw pic[double,draw] at (0, 1.0em) {infinity symbol={lower target=1.5,upper target=1.5}};
\end{tikzpicture}
\end{document}

The last thing that might be of interest is that I pass pic actions to the base style, every infinity, but I do so before the path change. Similarly one might remove it from the base style placing it into the call to draw instead as in \draw[pic actions, every infinity] .... The effect is the same either way, the latter being slightly more 'hard coded'. There is a caveat though if pic actions is placed after the path change as in every infinity={infinity dimensions/.cd, pic actions} or as \draw[every infinity, pica actions] then one must enable the line infinity dimensions/.serach also={/tikz, /pgf} otherwise you will get error messages indicating that the key is unrecognised.

Notes:

It wasn't initially obvious to me that pic actions really dislikes being under any path other then /tikz. You can pass it to say infinity dimensions/.style={} provided that the .search also handler is correctly set e.g. infinity dimensions/.search also={/tikz}. As it acts in this root, anything within pic actions is also bound to this root so upper target=... in infinity dimensions/.style{upper target=...} fails as it is now being called within the /tikz path and not /tikz/infinity dimensions. So anything contained within pic actions is executed within the /tikz path. Originally I thought pic actions were more like a container that one could pass around and unpack at will which was incorrect.

You must log in to answer this question.

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