# Accessing a style property in TikZ? [duplicate]

Possible Duplicate:
How to extract the value from a pgfkeys style element

Let us assume I have defined the following TikZ style:

\tikzset{
mystyle/.style={draw, fill=green, node distance=3mm}
}


and I want to draw the following picture:

To draw this, I use the following code:

\documentclass{article}

\usepackage{tikz}
\usetikzlibrary{calc, positioning}

\begin{document}
\begin{tikzpicture}[%
mystyle/.style={draw, node distance=3mm}
]
\node [mystyle] (n1) {1};
\node [mystyle, right=of n1] (n2) {2};
\node at ([yshift=-3mm] $(n1.south) !0.5! (n2.south)$) [mystyle, below] (n3) {3};
\end{tikzpicture}
\end{document}


Although it works, it has the problem that the distance (3mm) is defined twice -- once in the style and once in the figure itself.

Before, I've solved this by creating a new dimension register which defines the distance, but I would like to be able to extract the value from the style directly. As an example, I would like something like this:

\documentclass{article}

\usepackage{tikz}
\usetikzlibrary{calc, positioning}

\begin{document}
\begin{tikzpicture}[%
mystyle/.style={draw, node distance=3mm}
]
\node [mystyle] (n1) {1};
\node [mystyle, right=of n1] (n2) {2};
\node at ([yshift=-\styleproperty{mystyle/node distance}] $(n1.south) !0.5! (n2.south)$) [mystyle, below] (n3) {3};
\end{tikzpicture}
\end{document}


Is this possible to achieve?

-
Please ensure that your code snippets are fully compilable. It didn't take me long to realise you were using calc and positioning, but with more obscure libraries it can take longer to figure out and that makes it harder for people to know that they are answering the question well. –  Andrew Stacey Mar 29 '12 at 11:52
@AndrewStacey: Ah, didn't think about the required TikZ libraries. I assumed a fully working example wasn't necessary here, but indeed obscure library usage will cause much annoyance. I've updated the question accordingly. –  gablin Mar 29 '12 at 13:23
Full working examples are always nice: I cut-and-paste directly into a clean Emacs buffer and so it's nice to be able to just do C-y C-x C-f without having to think. Then I can see the problem straight away and make a quick assessment on whether or not I'll be able to help. –  Andrew Stacey Mar 29 '12 at 13:32
@Daniel: Oh yeah, it is! How come I didn't find that one during search?? XD –  gablin Mar 30 '12 at 7:01

## marked as duplicate by Daniel, Jake, percusse, Torbjørn T., Stefan Kottwitz♦Mar 31 '12 at 11:26

Thanks to Ryan Reich's Most Excellent PGFKeys tracing package (at How do I debug pgfkeys?), I found that the key node distance stores its value in the macro \tikz@node@distance. This means that it cannot be accessed via the "standard channels" for pgfkeys (namely \pgfkeyvalueof). Moreover, as the macro name has @s in it then it cannot be used as-is. So we have to define a wrapper to get the value of this macro.

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{calc,positioning}

% This bit was how I found out what was going on
%\usepackage{trace-pgfkeys}

%\pgfkeystracelevel{verbose}
%\tikzset{node distance=3mm}
%\pgfkeystracelevel{silent}

\makeatletter
\def\getnodedistance{\tikz@node@distance}
\makeatother

\begin{document}

\begin{tikzpicture}[%
mystyle/.style={draw, node distance=3mm}
]
\node [mystyle] (n1) {1};
\node [mystyle, right=of n1] (n2) {2};
\node [mystyle, below] at ([yshift=-\getnodedistance]$(n1.south) !0.5! (n2.south)$) (n3)
{3};
\end{tikzpicture}
\end{document}


This method doesn't easily generalise, but that's because pgfkeys can do whatsoever they like with the values that they are passed, including storing them in arbitrary macros. Sometimes you are lucky and they store them in keys in which case \pgfkeysvalueof{full key name} is what you want here. If a general macro is used, then you have to use that macro to access it.

(An alternative method would be to add some code to the original key call to store the value in another macro which you could use. I'd use this if the key used the argument in some non-trivial way which made it hard to extract the original value.)

Note: since the assignment node distance=3mm is local, you need to ensure that the mystyle key is invoked before the \getnodedistance macro is called. That's why I shifted the [mystyle,below] part to before the coordinate calculation. If you wanted to be able to specify the 3mm earlier in the document, I'd do all this in another way: store the 3mm in a separate key and then have both node distance and the yshift access this key. Something like:

\tikzset{
my global node distance/.initial=3mm,
mystyle/.style={
draw,
node distance=\pgfkeysvalueof{/tikz/my global node distance}
}
}

...

\node [mystyle,below] at ([yshift=-\pgfkeysvalueof{/tikz/my global node distance]...


EDIT (by percusse) :

Here are two more ways to include the macro assignment in the style declaration

1) Provide a length macro name option to save the value of node distance directly to that macro name(in this case mynodedist).

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{calc,positioning}
\makeatletter
\tikzset{ mystyle/.style={draw, node distance=3mm, save node distance to=mynodedist},
save node distance to/.code={\expandafter\newdimen\csname#1\endcsname%
}
\makeatother

\begin{document}
\begin{tikzpicture}
\node [mystyle] (n1) {1};
\node [mystyle, right=of n1] (n2) {2};
\node [mystyle, below] at ([yshift=-\mynodedist ]$(n1.south) !0.5! (n2.south)$) (n3) {3};
\end{tikzpicture}
\end{document}


2) You can do the regular style= and code= assignment of the same key set, for more disciplined key-value pairing which boils down to modifying only

\makeatletter
\tikzset{ mystyle/.style={draw, node distance=3mm},
}
\makeatother

-
I think using a /.code for mystyle on the spot would make the macro assignment a little more organized. –  percusse Mar 29 '12 at 12:18
@percusse Care to expand on that? I think I need to see it in full to understand your point (feel free to edit my answer if you don't want to provide an answer of your own). –  Andrew Stacey Mar 29 '12 at 12:37
Could you provide a full minimal example where you use \pgfkeysvalueof? I have trouble getting mine to compile. –  gablin Mar 29 '12 at 14:00
Found the problem: I must prepend "/tikz/" to the key I want to access. You should probably fix that in your answer. –  gablin Mar 29 '12 at 14:04
@gablin Sorry about that. I added the \pgfkeysvalueof bit as an afterthought and didn't actually test it. I've edited the answer as you suggested. –  Andrew Stacey Mar 29 '12 at 18:13

The question is interesting because Andrew and percusse gave interesting informations about \tikz@node@distance. I think it's not necessary to extract the value from the style directly in this case. How to extract is interesting but it's preferable to avoid this because TikZ gives you all the tools.

I 'm not a big fan of the positioning library but if you use it then I think the better way it's to use it till the end of your code. You want to use the value of the current node distancein this case I think below=of is preferable ! (instead of yshift)

I think the next code gives what you want to achieve

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{calc, positioning}

\begin{document}

\begin{tikzpicture}[%
every node/.style = {draw},
node distance     = 3mm
]
\node  (n1) {1};
\node [right=of n1] (n2) {2};
\path let \p1 = ($(n1.south) !0.5! (n2.south)$) in node[below=of \p1] (n3)  {3};
% more simpler : \node[below= of $(n1.south) !0.5! (n2.south)$] (n3) {3}; % (percusse)
\end{tikzpicture}

\end{document}


-
Now that you mention it, even \node[mystyle,below= of $(n1.south) !0.5! (n2.south)$] (n3) {3}; is sufficient. –  percusse Mar 31 '12 at 9:52
It's the first try that I made with an error (pgf cvs) but perhaps I made a syntax mistake. You are right, it's the good way ! –  Alain Matthes Mar 31 '12 at 11:12
Actually I didn't know that it is possible. I forgot to put the parentheses. Don't tell anyone :) I think this is better than accessing the keys. –  percusse Mar 31 '12 at 11:19
@percusse: By coincidence, I just realized the same thing I went here to mention it. But you beat me to it. =) –  gablin Mar 31 '12 at 12:53