# Use for loops to generate TikZ coordinates corresponding to linear combinations of vectors

I am trying to draw linear combinations of vectors. I started defining coordinates manually, but it's too time- and space-consuming:

\begin{center}
\pgfplotsset{compat=1.15}
{
\begin{tikzpicture}[scale=1]
\begin{axis}
[
% legend pos=outer north east,
grid,
xmin=-7, xmax=7,    ymin=-7,    ymax=7,
% xlabel = {$x$}, ylabel = {$y$},
xtick={-6,-5,...,6},
ytick={-6,-5,...,6},
xticklabels={-6,,-4,,-2,,0,,2,,4,,6,},
yticklabels={-6,,-4,,-2,,0,,2,,4,,6,},
clip=false,
grid = major, axis lines = middle,
axis line style={gray}
]
\coordinate (o) at (0,0);
\coordinate (c) at (1,2);
\coordinate (2c) at (2,4);
\coordinate (3c) at (3,6);
\coordinate (4c) at (4,8);
\coordinate (-c) at (-1,-2);
\coordinate (-2c) at (-2,-4);
\coordinate (-3c) at (-3,-6);
\coordinate (-4c) at (-4,-8);
\coordinate (d) at (1,1);
\coordinate (2d) at (2,2);
\coordinate (3d) at (3,3);
\coordinate (4d) at (4,4);
\coordinate (-d) at (-1,-1);
\coordinate (-2d) at (-2,-2);
\coordinate (-3d) at (-3,-3);
\coordinate (-4d) at (-4,-4);
\coordinate (c+d) at (2,3);
\coordinate (c+2d) at (3,4);
\coordinate (c+3d) at (4,5);
\coordinate (c+4d) at (5,6);
\coordinate (2d) at (2,2);

%total
\draw[line width=1pt, orange, -latex](o)--(c+2d) node[xshift=3mm, yshift=3mm]{$\vec{\bm{c}}+2\vec{\bm{d}}$};

\draw[line width=1pt, green, -latex](o)--(c) node[midway, xshift=-3mm, yshift=2mm]{$\vec{\bm{c}}$};
\draw[line width=1pt, violet, -latex](c)--(c+d) node[midway, xshift=-3mm, yshift=2mm]{$\vec{\bm{d}}$};
\draw[line width=1pt, violet, -latex](c+d)--(c+2d) node[midway, xshift=-3mm, yshift=2mm]{$\vec{\bm{d}}$};

\draw[line width=1pt, violet, -latex](o)--(d) node[midway, xshift=2mm, yshift=-2mm]{$\vec{\bm{d}}$};
\draw[line width=1pt, violet, -latex](d)--(2d) node[midway, xshift=2mm, yshift=-2mm]{$\vec{\bm{d}}$};
\draw[line width=1pt, green, -latex](2d)--(c+2d) node[midway, xshift=2mm, yshift=-2mm]{$\vec{\bm{c}}$};

\end{axis}
\end{tikzpicture}
}
\end{center}


I figured I could use for loops to accomplish this more efficiently:

I tried this, but it does not work:

\begin{center}
\pgfplotsset{compat=1.15}
{
\begin{tikzpicture}[scale=1]
\begin{axis}
[
% legend pos=outer north east,
grid,
xmin=-7, xmax=7,    ymin=-7,    ymax=7,
% xlabel = {$x$}, ylabel = {$y$},
xtick={-6,-5,...,6},
ytick={-6,-5,...,6},
xticklabels={-6,,-4,,-2,,0,,2,,4,,6,},
yticklabels={-6,,-4,,-2,,0,,2,,4,,6,},
clip=false,
grid = major, axis lines = middle,
axis line style={gray}
]
\coordinate (o) at (0,0);
\coordinate (c) at (1,2);
\coordinate (d) at (1,1);
\foreach \i in {-4, -3, ..., 4} {
\coordinate (\ic) at (\i, 2*\i);
\coordinate (\id) at (\i, \i);
\foreach \j in {-4, -3, ..., 4} {
\coordinate (\ic+\jd) at (\i+\j, 2*\i+\j);
}
}

%total
\draw[line width=1pt, orange, -latex](o)--(c+2d) node[xshift=3mm, yshift=3mm]{$\vec{\bm{c}}+2\vec{\bm{d}}$};

\draw[line width=1pt, green, -latex](o)--(c) node[midway, xshift=-3mm, yshift=2mm]{$\vec{\bm{c}}$};
\draw[line width=1pt, violet, -latex](c)--(1c+1d) node[midway, xshift=-3mm, yshift=2mm]{$\vec{\bm{d}}$};
\draw[line width=1pt, violet, -latex](1c+1d)--(1c+2d) node[midway, xshift=-3mm, yshift=2mm]{$\vec{\bm{d}}$};

\draw[line width=1pt, violet, -latex](o)--(d) node[midway, xshift=2mm, yshift=-2mm]{$\vec{\bm{d}}$};
\draw[line width=1pt, violet, -latex](d)--(0c+2d) node[midway, xshift=2mm, yshift=-2mm]{$\vec{\bm{d}}$};
\draw[line width=1pt, green, -latex](2d)--(1c+2d) node[midway, xshift=2mm, yshift=-2mm]{$\vec{\bm{c}}$};

\end{axis}
\end{tikzpicture}
}
\end{center}


So I have two questions:

1. How can I get this to work with a for loop instead of defining each coordinate manually?
2. Even the original solution doesn't work if I don't set compatibility backward with \pgfplotsset{compat=1.15}. Is there something about my code that needs to be updated to work with newer versions? What should I adjust to become forward-compatible?
• Try \i c etc. instead of \ic. You haven't defined \ic but only \i. And please post compilable code rather than a snippet.
– cfr
Commented Jun 17 at 18:02

In section 17.2.1 Syntax of the Node Command of pgfmanual.pdf you find that
\coordinate
is an abbreviation for
\path coordinate
while
\path … coordinate[⟨options⟩](⟨name⟩)at(⟨coordinate⟩) …;
is
\node[shape=coordinate][⟨options⟩](⟨name⟩)at(⟨coordinate⟩){},.

So a \coordinate actually is a named TikZ-node.

In the same section you also find that names of nodes can be referenced outside the local scopes wherein they are created.

So scoping (as with each iteration of a \foreach-command) is not an issue.

However, the proper timing of expansion is an issue.

You can use \expanded to get proper timing of expansion:

\documentclass{article}
\usepackage{pgfplots, bm}
\pgfplotsset{compat=1.15}

\begin{document}
\begin{center}%
\begin{tikzpicture}[scale=1]
\begin{axis}
[
% legend pos=outer north east,
grid,
xmin=-7, xmax=7,    ymin=-7,    ymax=7,
% xlabel = {$x$}, ylabel = {$y$},
xtick={-6,-5,...,6},
ytick={-6,-5,...,6},
xticklabels={-6,,-4,,-2,,0,,2,,4,,6,},
yticklabels={-6,,-4,,-2,,0,,2,,4,,6,},
clip=false,
grid = major, axis lines = middle,
axis line style={gray}
]
\coordinate (o) at (0,0);
\coordinate (c) at (1,2);
\coordinate (d) at (1,1);
\foreach \i in {-4, -3, ..., 4} {%
\expanded{%
\noexpand\coordinate (\i c) at (\i, 2*\i);
\noexpand\coordinate (\i d) at (\i, \i);
}%
\foreach \j in {-4, -3, ..., 4} {%
\expanded{%
\noexpand\coordinate (\i c+\j d) at (\i+\j, 2*\i+\j);
}%
}%
}
%total
\draw[line width=1pt, orange, -latex](o)--(1c+2d) node[xshift=3mm, yshift=3mm]{$\vec{\bm{c}}+\vec{\bm{d}}+\vec{\bm{d}}$};

\draw[line width=1pt, green, -latex](o)--(c) node[midway, xshift=-3mm, yshift=2mm]{$\vec{\bm{c}}$};
\draw[line width=1pt, violet, -latex](c)--(1c+1d) node[midway, xshift=-3mm, yshift=2mm]{$\vec{\bm{d}}$};
\draw[line width=1pt, violet, -latex](1c+1d)--(1c+2d) node[midway, xshift=-3mm, yshift=2mm]{$\vec{\bm{d}}$};

\draw[line width=1pt, violet, -latex](o)--(d) node[midway, xshift=2mm, yshift=-2mm]{$\vec{\bm{d}}$};
\draw[line width=1pt, violet, -latex](d)--(0c+2d) node[midway, xshift=2mm, yshift=-2mm]{$\vec{\bm{d}}$};
\draw[line width=1pt, green, -latex](2d)--(1c+2d) node[midway, xshift=2mm, yshift=-2mm]{$\vec{\bm{c}}$};

\end{axis}
\end{tikzpicture}%
\end{center}%
\end{document}


Alternatively don't define so many coordinates and use the calc-library instead.

Usually when you use the command \coordinate for specifying names for locations for later referencing, all location-data is related to the tikzpicture-environment's origin.

Within pgfplot's axis-environment via \coordinate you can specify x-values and y-values in relation to the axis-environment's origin for saving. However, even within pgfplot's axis-environment, location-data of named coordinates is calculated and saved for later reference in relation to the tikzpicture-environment's origin, not in relation to the axis-environment's origin.

Therefore, when using ($...$)-notation for calculating locations of coordinates and hereby referencing by their names coordinates that are already defined, the locations of the coordinates already defined are related to the tikzpicture-environment's origin, not related to the axis-environment's origin.
Thus the calculation must also take into account calculating direction vectors by subtracting the coordinates of the axis-environment's origin.

\documentclass{article}
\usepackage{pgfplots}
\pgfplotsset{compat=1.15}
\usetikzlibrary{calc}
\usepackage{bm}

\begin{document}
\begin{center}%
\begin{tikzpicture}%[scale=1]
\begin{axis}
[
% legend pos=outer north east,
grid,
xmin=-7, xmax=7,    ymin=-7,    ymax=7,
% xlabel = {$x$}, ylabel = {$y$},
xtick={-6,-5,...,6},
ytick={-6,-5,...,6},
xticklabels={-6,,-4,,-2,,0,,2,,4,,6,},
yticklabels={-6,,-4,,-2,,0,,2,,4,,6,},
clip=false,
grid = major, axis lines = middle,
axis line style={gray}
]

\coordinate (o) at (0,0);
\coordinate (c) at (1,2);
\coordinate (d) at (1,1);

%total
\draw[line width=1pt, orange, -latex](o)--($(c)+2*(d)-2*(o)$) node[xshift=3mm, yshift=3mm]{$\vec{\bm{c}}+\vec{\bm{d}}+\vec{\bm{d}}$};

\draw[line width=1pt, green, -latex](o)--(c) node[midway, xshift=-3mm, yshift=2mm]{$\vec{\bm{c}}$};
\draw[line width=1pt, violet, -latex](c)--($(c)+(d)-(o)$) node[midway, xshift=-3mm, yshift=2mm]{$\vec{\bm{d}}$};
\draw[line width=1pt, violet, -latex]($(c)+(d)-(o)$)--($(c)+2*(d)-2*(o)$) node[midway, xshift=-3mm, yshift=2mm]{$\vec{\bm{d}}$};

\draw[line width=1pt, violet, -latex](o)--(d) node[midway, xshift=2mm, yshift=-2mm]{$\vec{\bm{d}}$};
\draw[line width=1pt, violet, -latex](d)--($2*(d)-(o)$) node[midway, xshift=2mm, yshift=-2mm]{$\vec{\bm{d}}$};
\draw[line width=1pt, green, -latex]($2*(d)-(o)$)--($(c)+2*(d)-2*(o)$) node[midway, xshift=2mm, yshift=-2mm]{$\vec{\bm{c}}$};

\end{axis}
\end{tikzpicture}%
\end{center}%
\end{document}


Addendum to take into account the comment

I am a little confused about the logic for adding and subtracting the origin. Sometimes +(o), sometimes -(o), sometimes -2*(o). I feel like I am guessing and checking. What's the logic here?

It is never +(o). ;-)

• This seems simpler than the method given in the manual?
– cfr
Commented Jun 17 at 20:09
• I am a little confused about the logic for adding and subtracting the origin. Sometimes +(o), sometimes -(o), sometimes -2*(o). I feel like I am guessing and checking. What's the logic here? Commented Jun 18 at 3:10
• @EthanAlvaree The logic is that (o), (c) and (d) are location vectors where the origin is the origin of the picture environment, not the origin of the axis environment. Thus, for obtaining coordinates of startpoints/endpoints of the vector-arrows of your picture, outgoing from one of the location vectors (o) or (c) or (d), you add up direction vectors (oc) and/or (od) which are calculated from the location vectors as (oc) = (c)-(o) resp (od) = (d) - (o). Commented Jun 18 at 12:22
• @EthanAlvaree When you form these vector sums to get the coordinates of the respective points of the picture, you can, e.g., factor out the vector (o) and write as a product of the vector (o) and a negative scalar. Commented Jun 18 at 12:22

pgfplots provides special versions of \foreach loops, a coordinate system for accessing coordinates inside axis and an extremely relevant example on page 547 of the manual.

In addition, you need \i c as \ic is not defined, while you also want to avoid spurious spaces in specifying the values to loop over.

Putting this together:

\documentclass[border=10pt]{standalone}
\usepackage{pgfplots}
\pgfplotsset{compat=1.18}% works fine?
\begin{document}
\begin{tikzpicture}[scale=1]
\begin{axis}
[
grid,
xmin=-7, xmax=7,    ymin=-7,    ymax=7,
xtick={-6,-5,...,6},
ytick={-6,-5,...,6},
xticklabels={-6,,-4,,-2,,0,,2,,4,,6,},
yticklabels={-6,,-4,,-2,,0,,2,,4,,6,},
clip=false,
grid = major, axis lines = middle,
axis line style={gray}
]
\coordinate (o) at (0,0);
\coordinate (c) at (1,2);
\coordinate (d) at (1,1);
% pgfplots mnaual 547
\pgfplotsforeachungrouped \i in {-4,-3,...,4} {
\edef\tempb{\noexpand\coordinate (\i c) at (axis cs:\i,{2*\i});}\tempb
\edef\tempc{\noexpand\coordinate (\i d) at (axis cs:\i,\i);}\tempc
\pgfplotsforeachungrouped \j in  {-4,-3,...,4} {
\edef\tempa{%
\noexpand\coordinate (\i c+\j d) at (axis cs:{\i+\j},{2*\i+\j});
}\tempa
}
}
\def\bm#1{#1}
%total
\draw[line width=1pt, orange, -latex](o)--(1c+2d) node[xshift=3mm, yshift=3mm]{$\vec{\bm{c}}+\vec{\bm{d}}$};

\draw[line width=1pt, green, -latex](o)--(c) node[midway, xshift=-3mm, yshift=2mm]{$\vec{\bm{c}}$};
\draw[line width=1pt, violet, -latex](c)--(1c+1d) node[midway, xshift=-3mm, yshift=2mm]{$\vec{\bm{d}}$};
\draw[line width=1pt, violet, -latex](1c+1d)--(1c+2d) node[midway, xshift=-3mm, yshift=2mm]{$\vec{\bm{d}}$};

\draw[line width=1pt, violet, -latex](o)--(d) node[midway, xshift=2mm, yshift=-2mm]{$\vec{\bm{d}}$};
\draw[line width=1pt, violet, -latex](d)--(0c+2d) node[midway, xshift=2mm, yshift=-2mm]{$\vec{\bm{d}}$};
\draw[line width=1pt, green, -latex](2d)--(1c+2d) node[midway, xshift=2mm, yshift=-2mm]{$\vec{\bm{c}}$};
\end{axis}
\end{tikzpicture}
\end{document}


• Thanks, cfr! What is requiring \pgfplotsset{compat=1.15}? Is there some syntax with this code that needs to be updated to work with \pgfplotsset{compat=newest}? Commented Jun 17 at 21:12
• @EthanAlvaree See edit. It doesn't require it as far as I can tell. Setting 1.18 (i.e. the newest) works fine for me. You do need to set this in the preamble though - you can't do it after \begin{document}.
– cfr
Commented Jun 17 at 22:31