In a tikzpicture, how can I “shift” by a multiple of the current x-vector (say)?

Suppose that I have a tikzpicture begun like this:

\begin{tikzpicture}[x = 20mm, y = 10mm]


Now let us suppose that I want to put a subpart of the picture inside a "scope" environment and I want all of that part of the picture to be shifted to the right by 40mm, that is, by twice the current x-vector. But should I later change the x-vector in the "tikzpicture" options, I will want the shift amount to respect the new x-vector. For example, if I changed the x-vector from 20mm to 15mm, I would want the subpicture to then automatically be shifted by 30mm instead of 40mm, without me having to modify the "scope" options.

If I do this:

\begin{scope}[xshift = 2]


then TikZ interprets this to mean that I want to shift right by a distance of 2pt, that is, the "2" is not interpreted as a multiple of the current x-vector. Conceptually, I want something like

\begin{scope}[xshift = 2 * \x]


but I don't know what the correct way is to express this to TikZ. How can I do this?

I accepted the answer supplied by Jake, but here is how to use his technique to define a key that makes a one-dimensional shift very straightforward. Put this in the document preamble:

\tikzset{myxshift/.style = {shift = {(#1, 0)}}}
\tikzset{myyshift/.style = {shift = {(0, #1)}}}


Now you can do something like this:

\begin{scope}[myxshift = 2]


There's no need for extracting the unit lengths: If you use shift={(<x>,<y>)}, the unit vectors will be used automatically (unlike using xshift and yshift, which expect lengths).

\documentclass{article}

\usepackage{tikz}

\begin{document}

\begin{tikzpicture}[x=2cm,y=1cm]
\node[draw] at (-3.5cm,0.5) {$x = 2$ cm};

\begin{scope}[shift={(2,0)}]
\draw (0,0) node[below] {2} -- (0,1);
\end{scope}

\begin{scope}[shift={(0,0)}]
\draw (0,0) node[below] {0} -- (0,1);
\end{scope}

\begin{scope}[shift={(-1,0)}]
\draw (0,0) node[below] {-1} -- (0,1);
\end{scope}
\end{tikzpicture}

\begin{tikzpicture}[x=1cm,y=1cm]
\node[draw] at (-3.5cm,0.5) {$x = 1$ cm};

\begin{scope}[shift={(2,0)}]
\draw (0,0) node[below] {2} -- (0,1);
\end{scope}

\begin{scope}[shift={(0,0)}]
\draw (0,0) node[below] {0} -- (0,1);
\end{scope}

\begin{scope}[shift={(-1,0)}]
\draw (0,0) node[below] {-1} -- (0,1);
\end{scope}
\end{tikzpicture}
\end{document}

• Ah, I thought there surely must be a simple way of doing this. Thank you Peter and T. Verron for your help, but I feel that this answer is the most straightforward solution to the problem, so I am accepting it. – Hammerite Dec 2 '12 at 5:28
• @Hammerite: Seriously, you don't like my convoluted solution? Where is the fun is using something so simple and elegant? If people look at your code they are going to think that you did not do much work, but with my solution you'd get a "wow, that was a lot of work", surely that should count for something :-) – Peter Grill Dec 2 '12 at 5:46
• You mention that xshift expects a length. I see that is true, but where is the default length documented? Why is the default length not determined by the picture (like coordinates are)? – Alan Jul 5 '16 at 14:58

You can extract the length of the vector (1,0) and use that length to apply the shift:

Notes:

• Probably with some \expandafter magic this can all be one within the one macro.

Code:

\documentclass{article}
\usepackage{tikz}

% https://tex.stackexchange.com/questions/33703/extract-x-y-coordinate-of-an-arbitrary-point-in-tikz
\newlength{\XCoord}
\newlength{\YCoord}
\newcommand*{\ExtractCoordinate}[1]{\path (#1); \pgfgetlastxy{\XCoord}{\YCoord};}%
\newlength{\ScaledXShift}
\newcommand*{\ApplyXVec}[1]{%
\ExtractCoordinate{1,0}%
\pgfmathsetlength{\ScaledXShift}{#1*\XCoord}%
%\ScaledXShift%
}

\begin{document}
\begin{tikzpicture}[x = 20mm, y = 10mm]
\draw [blue, ultra thick, <->](0,0.5) -- (0,-0.5);
\begin{scope}[xshift = 2]
\draw [red,ultra thick,->] (0,0) -- (1,0);
\end{scope}
\end{tikzpicture}

\begin{tikzpicture}[x = 5mm, y = 10mm]
\draw [blue, ultra thick, <->](0,0.5) -- (0,-0.5);
\ApplyXVec{2}%
\begin{scope}[xshift = \ScaledXShift]
\draw [red,ultra thick,->] (0,0) -- (1,0)
node [right, black] {xshift = 2x, x=5mm};
\end{scope}
\end{tikzpicture}

\begin{tikzpicture}[x = 10mm, y = 10mm]
\draw [blue, ultra thick, <->](0,0.5) -- (0,-0.5);
\ApplyXVec{1}%
\begin{scope}[xshift = \ScaledXShift]
\draw [red,ultra thick,->] (0,0) -- (1,0)
node [right, black] {xshift = 1x, x=10mm};
\end{scope}
\end{tikzpicture}

\begin{tikzpicture}[x = 10mm, y = 10mm]
\draw [blue, ultra thick, <->](0,0.5) -- (0,-0.5);
\ApplyXVec{2}%
\begin{scope}[xshift = \ScaledXShift]
\draw [red,ultra thick,->] (0,0) -- (1,0)
node [right, black] {xshift = 2x, x=10mm};
\end{scope}
\end{tikzpicture}
\end{document}

• Goodness, I did not realise that the solution would be so complex. Thank you for your examples. I shall accept the answer presently assuming no-one offers an alternative method. I shall have to see whether I can define my own key (something like "myxshift = ...") that does this stuff behind the scenes, but if that's not feasible then I guess having to call a macro like your "\ApplyXVec" is not too much of a burden. – Hammerite Dec 1 '12 at 7:38
• @Hammerite: It's not really that complicated, but would have been helpful if a test case was provided as I think that makes it appear more complicated. Yeah, you should be able to define a style myxshift to hide this, but my attempts to do that failed. – Peter Grill Dec 1 '12 at 7:53
• I apologise for not providing a test case. I assumed that there must exist syntax to do this that I simply did not know, and thus that construction of examples would not be necessary. – Hammerite Dec 1 '12 at 7:56

Another (maybe easier?) solution is to use the calc library

\usetikzlibrary{calc}


and naturally translate your english question into a tikz instruction :

\pgfmathsetmacro\myscalingfactor{2}
\begin{scope}[shift={(${\myscalingfactor}*(1,0)$)}] % The factor * the vector
\end{scope}


A MWE (less pretty than Peter's):

\documentclass{article}

\usepackage{tikz}

\usetikzlibrary{calc}

\begin{document}

\begin{tikzpicture}[x=2cm,y=1cm]
\node[draw] at (-3.5cm,0.5) {$x = 2$ cm};

\pgfmathsetmacro\myscalingfactor{2}
\begin{scope}[shift={(${\myscalingfactor}*(1,0)$)}]
\draw (0,0) node[below] {2} -- (0,1);
\end{scope}

\pgfmathsetmacro\myscalingfactor{0}
\begin{scope}[shift={(${\myscalingfactor}*(1,0)$)}]
\draw (0,0) node[below] {0} -- (0,1);
\end{scope}

\pgfmathsetmacro\myscalingfactor{-1}
\begin{scope}[shift={(${\myscalingfactor}*(1,0)$)}]
\draw (0,0) node[below] {-1} -- (0,1);
\end{scope}
\end{tikzpicture}

\begin{tikzpicture}[x=1cm,y=1cm]
\node[draw] at (-3.5cm,0.5) {$x = 1$ cm};

\pgfmathsetmacro\myscalingfactor{2}
\begin{scope}[shift={(${\myscalingfactor}*(1,0)$)}]
\draw (0,0) node[below] {2} -- (0,1);
\end{scope}

\pgfmathsetmacro\myscalingfactor{0}
\begin{scope}[shift={(${\myscalingfactor}*(1,0)$)}]
\draw (0,0) node[below] {0} -- (0,1);
\end{scope}

\pgfmathsetmacro\myscalingfactor{-1}
\begin{scope}[shift={(${\myscalingfactor}*(1,0)$)}]
\draw (0,0) node[below] {-1} -- (0,1);
\end{scope}
\end{tikzpicture}


\end{document}

• Ok, my image is prettier, but your solution is much better! – Peter Grill Dec 1 '12 at 10:13
• You don't need to extract the scaling factor. You can just say shift={(2,0)}, which will take the scaling into account correctly. – Jake Dec 1 '12 at 12:16
• @Jake : It seems the OP wanted to parametrize his shifting by the factor. For example, if later he wants to adapt this process to the vector (3.14,1.41) with a scaling factor of \pgfmathsqrt{10}, it will be easier to separate the scaling factor from the vector, rather than computing the exact coordinates (whether it be by hand or by pgfmath). – T. Verron Dec 1 '12 at 12:20
• @T.Verron: But you can use math expressions in coordinates. So if the OP has set x=3.14cm, y=1.41cm, he can simply say shift={ ({sqrt(10)} , 0) } to shift the scope by sqrt(10)*3.14cm. – Jake Dec 1 '12 at 12:31
• @Jake : I meant in case he wants to do something like shift={(${sqrt(10)}*(3.14,1.41)$)}, this syntax will be much cleaner than the (equivalent) shift={(sqrt(10)*3.14,sqrt(10)*1.41)}, and also much easier to adapt, should he decide to change the factor or the vector later. Anyway, the question is specifically about scaling a vector, that's why I chose that syntax in the first place. However, I agree your option is perfectly valid for the job, and depending on the task, could prove more convenient. – T. Verron Dec 1 '12 at 13:29