13

Update: this is now a bug report on sf.net.

I think I understand the rules for special characters in pgfkeys key arguments: If it contains any of {,, =, ]}, it must be protected by putting the entire argument in braces. In that case, the braces are stripped by pgfkeys and anything inside is preserved, including surrounding whitespace.

Now, I have the following MWE using minimum {width,height,size} as a representative trio:

\documentclass[tikz]{standalone}

 \tikzset{minimum width= {max(1,2)} } % (1) works
%\tikzset{minimum width=  max(1,2)  } % (2) doesn't work because of comma
%\tikzset{minimum size =  max(1,2)  } % (3) doesn't work (expected)
%\tikzset{minimum size = {max(1,2)} } % (4) doesn't work (but I think it should)
%\tikzset{minimum size ={{max(1,2)}}} % (5) doesn't work (desperate attempt)

\begin{document}\end{document}

It's clear to me that (2) and (3) can't work because that will confuse the parser. I can explain why (4) doesn't work by looking at the definition in pgfmoduleshapes.code.tex:

\pgfset{minimum size/.style={/pgf/minimum width=#1,/pgf/minimum height=#1}}

By substituting the argument with stripped braces, which is now max(1,2), for #1, we get invalid pgfkeys syntax. Everything works as expected if I change the definition to

\pgfset{minimum size/.style={/pgf/minimum width={#1},/pgf/minimum height={#1}}}

. Is this a bug in the shapes module or does this change have a drawback I didn't see?

As a side note, I tried (5) as a workaround, but that also doesn't work. Why?


If a more practical MWE is desired: I was originally messing around with Draw a node as a square with TikZ and got to the following code:

\documentclass[border=2mm,tikz]{standalone}

\tikzset{square/.style={
    minimum width={max(width("#1") + 2 * \pgfshapeinnerxsep, height("#1") + depth("#1") + 2 * \pgfshapeinnerysep)},
    minimum height={max(width("#1") + 2 * \pgfshapeinnerxsep, height("#1") + depth("#1") + 2 * \pgfshapeinnerysep)},
    node contents={#1},
}}

\begin{document}
    \begin{tikzpicture}
        \node[draw,square=Hello];
    \end{tikzpicture}
\end{document}

I would like to use minimum size to avoid duplicating the expression.

  • 7
    I don't think you show sufficient desperation, young padawan. It works if you try \tikzset{minimum size ={{{{{{max(1,2)}}}}}}}. – Loop Space Apr 14 '16 at 13:00
  • 5
    Also worked: \tikzset{minimum size ={{max(1,2)}{}}} (the empty group prevents the inner braces from being stripped by macro parameter expansion). – Loop Space Apr 14 '16 at 13:03
  • 5
    Last one (for now): \tikzset{minimum size =max{(1,2)}}. A quick check with \pgfmathparse shows that max{(1,2)} works as it should. – Loop Space Apr 14 '16 at 13:05
  • 2
    Found another one: \tikzset{/pgf/minimum size ={{{{max(1,2)}}}}} (that's two fewer braces). Without the /pgf/ prefix, it tries /tikz/minimum size first and when that doesn't work it gets passed to /pgf/minimum size and presumably that strips off another couple of braces. So I guess the point is that these keys get bounced around quite a bit in the key handling and lots of braces get stripped off (and I suspect it would be hard to ensure that they didn't). I think your fix for pgfmodule.shapes.code.tex would be the "right" answer. – Loop Space Apr 14 '16 at 13:30
  • 2
    Sounds a reasonable plan. By the way, I think that the protection of ] is more to do with the fact that keys are often set in the optional argument to a tikzpicture environment or drawing command and so any ] needs protecting otherwise it is taken as the ending square bracket. – Loop Space Apr 14 '16 at 13:57
3

Apart from suggestions in comments, mine is

\tikzset{
    square/.style={
        /utils/exec={
            \pgfmathsetmacro\mysize{
                max(width("#1")+2*\pgfshapeinnerxsep,
                    height("#1")+depth("#1")+2*\pgfshapeinnerysep)
            }
        },
        minimum width=\mysize,
        minimum height=\mysize,
        node contents={#1}
    }
}

And the reason is simple: even if you can pass a complicated math expression as the argument, it will be calculated multiple times and waste some time.

Besides, the same math expression does not give the identical result from time to time. An interesting example is

\tikz\draw circle(rnd);

Is it a circle? or ellipse?

Comment

Yes, it is a bug. It should have use ={#1} instead.

A brutal search of \=\#\d\, over the whole PGF gives the following results

  • \tikzset{radius/.style={/tikz/x radius=#1,/tikz/y radius=#1}}
    
  • \tikzset{cs/radius/.style={/tikz/cs/x radius=#1,/tikz/cs/y radius=#1}}
    
  • verbose/.style={
      verbose IO=#1,
      verbose optimize=#1,
      verbose up to date=#1,
    },
    
  • \def\tikz@lib@chainin@#1[#2]{\path[late options={name=#1,on chain,every chain in/.try,#2}]}
    
  • shape start size/.style={%
      shape start width=#1,
      shape start height=#1%
    },%
    shape end size/.style={%
      shape end width=#1,
      shape end height=#1%
    },%
    shape size/.style={%
      shape start size=#1,
      shape end size=#1%
    },%
    shape width/.style={%
      shape start width=#1,
      shape end width=#1
    },
    shape height/.style={%
      shape start height=#1,
      shape end height=#1
    }
    
  • trapezium angle/.style={
      /pgf/trapezium left angle=#1,
      /pgf/trapezium right angle=#1
    },%
    
  • \pgfkeys{/pgf/chamfered rectangle sep/.style={%
      /pgf/chamfered rectangle xsep=#1,/pgf/chamfered rectangle ysep=#1}%
    }
    
  • zerofill/.style={/pgf/number format/fixed zerofill=#1,/pgf/number format/sci zerofill=#1},
    
  • radius/.style={start radius=#1,end radius=#1},
    
  • /pgf/segment amplitude/.style={/pgf/decoration={amplitude=#1,shape height=2*#1}},
    
  • /pgf/segment object length/.style={/pgf/decoration={shape width=#1,radius=#1}}}
    
  • inner sep/.style={/pgf/inner xsep=#1,/pgf/inner ysep=#1},
    
  • minimum size/.style={/pgf/minimum width=#1,/pgf/minimum height=#1},
    

Some results from .def files and datavisualization library are omitted. I am not saying that those lines above contain bugs. But it might be fun to try. One might also want to try \=\#\d\} and \=\#\d.*\,

Have fun

  • rnd is an exception. It is called twice once for x radius and once for y radius. – percusse Nov 29 '16 at 3:02
  • @percusse no it is not. That is just a funny example to emphasize my point. Back to OP's example: height is not stable because it is implicitly affected by font settings; \pgfshapeinnerysep is not stable either. Nonetheless I have to admit that in this case it is almost impossible to produce different result. – Symbol 1 Nov 29 '16 at 3:11
  • I mean implicitly you are calling rnd twice. In your recent example it's just depending on the font size because the units are font dependent. But still the same quantity. That's different than what I mean. – percusse Nov 29 '16 at 3:38
  • That's definitely a practical solution. The node text is still set at least four times, so of course it's still not a performance miracle. I still believe that the behavior of minimum size is a bug. – wrtlprnft Nov 30 '16 at 7:55
  • @wrtlprnft please see my update – Symbol 1 Nov 30 '16 at 12:09

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.