16

When using the scale option in \tikz[xscale=2] etc, is there any way to access the scale setting from within the TikZ environment?

6
  • Not the actual 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? Dec 23, 2013 at 21:37
  • 1
    I don't know if this is what you need but you can apply scale only to a block using \begin{scope}[scale=2]...\end{scope}.
    – Sigur
    Dec 23, 2013 at 21:53
  • 2
    Usually I do this : \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.
    – remjg
    Dec 24, 2013 at 9:45
  • @AndrewStacey I believe your comment is actually the answer. Dec 24, 2013 at 11:02
  • 1
    @ChristianFeuersänger I was waiting for clarification from the OP. If kiwi really wants to know what was passed in via xscale then it could be done by hacking the xscale key, but if what kiwi wants to do could be accomplished by knowing the transform matrix then that's a better solution. Dec 24, 2013 at 12:03

2 Answers 2

5

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

enter image description here

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) ).

2

The answer to this depends on what your purpose is in saving the xscale. There are two possibilities that I can think of:

  1. You want to know what was passed in via xscale.
  2. 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:

  1. You apply xscale=2 and then apply a rotation of π/2 (anticlockwise). The resulting matrix is

    [0 -1]
    [2  0]
    
  2. 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:

  1. To store the accumulated values passed to xscale, simply store them before passing them in,
  2. To extract the xscale from the transformation matrix, use the PGF commands for accessing the matrix, figure out what you mean by xscale an arbitrary matrix, and then compute it from the retrieved values.

You must log in to answer this question.

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