9

Consider the following MWE:

\documentclass[varwidth,tightpage,border=1bp]{standalone}

\usepackage{tikz}
\pagecolor{yellow!15} % ignored with preview, but not w/ varwidth

\begin{document}

  \begin{tikzpicture}

    \tikzset{/tikz/line width=1cm} % no effect
    \draw %[/tikz/line width=1cm] % has effect here
      (0,0) -- ++(1,0)
      node[fill,scale=0.5](A){};

    \pgfkeysgetvalue{/tikz/line width}{\tmp}
    \typeout{tmpX \tmp \meaning\tmp}

  \end{tikzpicture}

\end{document}

My first question is: here I'm trying to \tikzset{/tikz/line width=1cm}, but it has no effect (only on document size); the output is:

test03a.png

If I use the \draw[/tikz/line width=1cm], then there is effect, and the output is:

test03b.png

So, the question is - how come /tikz/line width doesn't have any effect? I would have thought it is a "master" key/variable of sorts (which kicks in, if nothing else is specified).

But even more important for me is - how do I read tikz/pgf keys? As you can see, I'm trying with \pgfkeysgetvalue{/tikz/line width}{\tmp}, but when I try to print it to stdout, I get this:

tmpX \tmp \relax

... which means that \tmp in unexpandable, probably because it has been "let" to \relax; and so I cannot read any information in /tikz/line width.

So, how can I read TikZ/PGF keys - in an expandable format, so I can use them in code?


EDIT: After reading Simple example of pgfkeys, I simply tried .initial:

\tikzset{/tikz/line width/.initial=1cm} 

... and afterwards, the stdout printout is:

tmpX 1cmmacro:->1cm

... which means my syntax for reading keys was correct - but apparently, the key /tikz/line width did not exist, even if I tried to "set" it?!

My question then becomes - what controls the line width of the \draw in the case when we do not specify anything, and how can I find and print the corresponding key values (if they exist)?


possibly related:

3
  • 2
    \tikzset{/tikz/<key>} sets the key /tikz/tikz/<key> either use \pgfkeys or remove the /tikz/
    – percusse
    Jun 16, 2014 at 18:40
  • Hah! Thanks, @percusse - had no idea the paths work in this way... Just tested it though, still have to use \tikzset{line width/.initial=1cm} to get an effect as described in the OP... Cheers!
    – sdaau
    Jun 16, 2014 at 18:55
  • 2
    line width doesn't hold a value. Instead it sets the length \pgflinewidth. You might want to read that dimen instead of reading a key because the dimen can change without changing the key value.
    – percusse
    Jun 16, 2014 at 19:11

1 Answer 1

9

Not every key sets a value.

A key can execute arbitrary code. If we look in tikz.code.tex then we see that when you invoke \tikzset{line width=2pt} then it doesn't set a value, it invokes \tikz@semiaddlinewidth{2pt}. This, in turn, expands to \tikz@addoption{\pgfsetlinewidth{2pt}}\pgfmathsetlength\pgflinewidth{2pt}.

There are two things going on here. One is that \pgfsetlinewidth is set up to be invoked at a later time. The other is that \pgflinewidth is set to the desired width. Now, \pgfsetlinewidth is the Real McCoy here. It sets the line width down in the depths of PGF's subsystem. All the messing around with \pgflinewidth doesn't actually set the real line width. It needs a genuine call to \pgfsetlinewidth to do this.

But the key /tikz/line width does not directly call \pgfsetlinewidth. It sets it up to be invoked at a later time. This is what \tikz@addoption does. These options get invoked once the path has been constructed and before it is rendered. But the option list is blanked at the start of a path construction. So the effect of the \tikz@addoption is nullified by the following \draw command before it has a chance to take effect.

You could do \tikzset{every path/.append style={line width=\pgflinewidth}} to ensure that the ambient line width is used as the default line width for every path. Or you could define a new key, \tikzset{ambient line width/.code={\pgfsetlinewidth{#1}}} (no need to explicitly set \pgflinewidth here).

As Paul Gaborit noted in the comments, you can achieve a change of line width for a group of paths by putting them in a scope and setting the line width in the optional argument to the scope. That is,

\begin{scope}[line width=1cm]
...
\end{scope}

sets the line width to 1cm for all the intervening paths.

The reason for this is that the optional arguments to the scope environment are passed to \tikzset and then immediately after, the token list \tikz@options is expanded. This means that the part of the line width key that is hidden in the \tikz@options token list is actually executed and therefore the line width is set properly deep in the heart of PGF.

4
  • Many thanks for the answer, @LoopSpace - it explains why I got the results that I did... Cheers!
    – sdaau
    Jun 16, 2014 at 19:17
  • To fix the line width of multiple paths, you can use line width as a scope option... Jun 18, 2014 at 6:11
  • @PaulGaborit I didn't know that! Looking at the code, the important part is that \begin{scope}[<stuff>] includes \tikzset{<stuff>}\tikz@options so the \tikz@addoption part of the line width=<length> key does get executed when the scope starts, setting the line width properly. I'll edit that into my answer as it's a useful work-around. Jun 18, 2014 at 6:59
  • Why is this excellent explanation missing in the TikZ manual? I've searched for hours...
    – lemzwerg
    Oct 7, 2022 at 23:43

You must log in to answer this question.

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