When using the scale option in \tikz[xscale=2]
etc, is there any way to access the scale setting from within the TikZ environment?
2 Answers
As Andrew says, you can use the transform matrix, which is an accumulation of all transformations currently applied to the current scope. The relevant details are found in Sections 104.2.1 and 104.2.4 of the PGF Manual (v3.0.0).
I defined a command \getmytransformmatrix
that stores PGF's internal representation of the transform matrix into the macros \mya
, \myb
, \myc
, \myd
, \mys
, and \myt
. These correspond to the coordinate transformation (x,y) --> (a*x + b*y + s, c*x + d*y +t)
. So the accumulated xscale
and yscale
(global CS basis) are stored in \mya
and \myd
, respectively. Similarly, the dimensions xshift
and yshift
are stored in \mys
and \myt
, respectively.
These are not persistent across scope boundaries/levels, so the command \getmytransformmatrix
must appear in every scope in which you wish to use the information.
The Code (with brief illustration)
\documentclass{standalone}
\usepackage{tikz}
\newcommand\getmytransformmatrix{%
\pgfgettransformentries{\mya}{\myb}{\myc}{\myd}{\mys}{\myt}%
% coordinate (x,y) is transformed to (ax + by + s, cx + dy + t)
}
\newcommand\drawmyaxes[1][]{% just for convenience
\draw (0,0) -- ++(1,0) node[right] {$x#1$};
\draw (0,0) -- ++(0,1) node[above] {$y#1$};
}
\newcommand\myvar[2]{\texttt{#1~=~#2}} % just for convenience
\begin{document}
\begin{tikzpicture}[xshift=2pt]
\getmytransformmatrix
\drawmyaxes
\node[align=left] at (-5,0) {Outside the scope, we have\\
\myvar{xscale}{\mya}, \myvar{yscale}{\myd}.};
\begin{scope}[yshift=-5pt,rotate=45]
\getmytransformmatrix
\drawmyaxes[']
\node[align=left] at (-1,-1) {Inside the scope, we have\\
\myvar{xscale}{\mya}, \myvar{yscale}{\myd}.\\
We also see that \myvar{xshift}{\mys}\\
and \myvar{yshift}{\myt}.};
\end{scope}
\node[align=left] at (5,0) {Outside the scope again, we have\\
\myvar{xscale}{\mya}, \myvar{yscale}{\myd}.};
\end{tikzpicture}
\end{document}
The Output
Note that the matrix is not "remembered" outside the scope, and that this shows the accumulated transformation (xshift=2pt
from the original environment and yshift=-5pt
from the scope).
The additional variables b
and c
could be used for other calculations; for example, to compute the effective rotation (atan(\myd/\mya)
would only work from (-90,90) ).
The answer to this depends on what your purpose is in saving the xscale
. There are two possibilities that I can think of:
- You want to know what was passed in via
xscale
. - You want to know the
xscale
of the current scope.
The first is quite easy, the second depends on what you mean by xscale
.
The reason that the first isn't trivial is because TikZ does not bother to save the value that you pass in, it simply applies it and then forgets it. So you need to add a wrapper around the xscale
key which saves the value for later use. Here's some code for that:
\documentclass{article}
%\url{http://tex.stackexchange.com/q/151147/86}
\usepackage{tikz}
\tikzset{
saved xscale/.initial=1,
save xscale/.style={
xscale=#1,
save the xscale=#1
},
save the xscale/.code={%
\pgfmathparse{#1 * \pgfkeysvalueof{/tikz/saved xscale}}%
\pgfkeysalso{saved xscale/.expand once=\pgfmathresult}%
}
}
\begin{document}
\begin{tikzpicture}
\begin{scope}[save xscale=2]
\node at (0,0) {\pgfkeysvalueof{/tikz/saved xscale}};
\begin{scope}[save xscale=2]
\node at (1,0) {\pgfkeysvalueof{/tikz/saved xscale}};
\end{scope}
\end{scope}
\node at (2,0) {\pgfkeysvalueof{/tikz/saved xscale}};
\end{tikzpicture}
\end{document}
(This may not be the most elegant way to achieve this.)
The difficulties with the second are because TikZ can apply any affine transformation to parts of a drawing. So you have to come up with a meaning for xscale
for an arbitrary affine transformation. Consider the two following scenarios:
You apply
xscale=2
and then apply a rotation of π/2 (anticlockwise). The resulting matrix is[0 -1] [2 0]
You apply the rotation first and then do
yscale=2
. The resulting matrix is[0 -1] [2 0]
So these two operations lead to the same matrix. Does that matrix have xscale
equal to 2
or yscale
equal to 2
? Or are both 0
?
Now consider doing the rotation and then xscale=2
. This yields:
[0 -2]
[1 0]
So for all of these scenarios you have to decide what xscale
should be. There are reasonable definitions, but precisely what will depend on what you want to do with them.
Thus the best you can do is to examine the matrix as a whole and compute some number that works for whatever it is that you want to do, but as this is not specified in the question then it is not feasible to answer that.
To get the entries of the matrix itself (well, the matrix and the translation), you can use the PGF command \pgfgettransformentries
. Then do what you like with them. For example, if you want to know the overall scale, you could take the square root of the absolute value of its determinant. If you want to know the length of the vector that (1,0)
eventually becomes, you could compute that.
In summary:
- To store the accumulated values passed to
xscale
, simply store them before passing them in, - To extract the
xscale
from the transformation matrix, use the PGF commands for accessing the matrix, figure out what you mean byxscale
an arbitrary matrix, and then compute it from the retrieved values.
xscale
passed in, but you can get the current transform matrix (ie the accumulation of all the transformations that you've specified). Would that be sufficient to your needs?\begin{scope}[scale=2]...\end{scope}
.\def\scaleFactor{2}\begin{tikzpicture}[scale=\scaleFactor]...\end{tikzpicture}
Then I can access it later using\scaleFactor
. I would love to have a more elegant solution, especially if I have multiple scopes and scale factors.xscale
then it could be done by hacking thexscale
key, but if what kiwi wants to do could be accomplished by knowing the transform matrix then that's a better solution.