3

I want a long list of items, each of which is a list {x,y,a,b} where (x,y) specifies a point at which to place a dot and the other items have to do with how this dot will be treated. I expected that

\def\elts{
  {14,6,3,3},    
  {14,2,100,1}    
}

\foreach \e in \elts
  \draw [fill] (\e[0],\e[1]) circle [radius=0.05];

would put filled circles at (14,6) and at (14,2). Instead, they are at (13,5) and (14,2). Playing with this, I get a great variety of wrong results with no sensible pattern. Clearly \e[2] and \e[3] affect the results. What gives? I thought the \foreach would set \e = {14,6,3,3}, access the first two elements in it, then set \e = {14,2,100,1} and access the first two elements in it. This is not what I see.

Here's a small working (failing) sample which has a grid and numbering to make it easy to see the problem.

\documentclass{article}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}

\draw[color=lightgray] (8,0) grid [step=4]  (16,8);

\foreach \n in {8,12,16}
\node [below] at (\n,0) {$\n$};

\foreach \s in {0,4,8}
\node [left] at (8,\s) {$\s$};

\def\elts{
{14,6,3,3},     %% Should produce a dot at (14,6), not at (13,5) 
{16,4,15,8},    %% Try changing the 15 to a 7 for puzzlement.
{14,2,100,1}    %% (14,2) as intended
}

\foreach \e in \elts
\draw [fill] (\e[0],\e[1]) circle [radius=0.05];

\end{tikzpicture}
\end{document}

Here's what this produces for me using TeXShop 3.62 on OS X 10.11.6. Dots should be at (14,6), (16,4) and (14,2).   Instead they are at (13,5), (10,-2) and (14,2)

3

The "wrong" results come, unsurprisingly, from an incorrect syntax. You have additional spaces and an array requires extra braces. I added them when I define \mye, but you could also add them otherwise.

\documentclass{article}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}

\draw[color=lightgray] (8,0) grid [step=4]  (16,8);

\foreach \n in {8,12,16}
\node [below] at (\n,0) {$\n$};

\foreach \s in {0,4,8}
\node [left] at (8,\s) {$\s$};

\def\elts{% see all the % I added to kill spaces
{14,6,3,3},%     %% Should produce a dot at (14,6), not at (13,5) 
{16,4,15,8},%    %% Try changing the 15 to a 7 for puzzlement.
{14,2,100,1}%    %% (14,2) as intended
}

\foreach \e in \elts
{\edef\mye{{\e}}
\pgfmathsetmacro{\myx}{\mye[0]}
\pgfmathsetmacro{\myy}{\mye[1]}
\draw [fill] (\myx,\myy) circle [radius=0.05];
}
\end{tikzpicture}
\end{document}

enter image description here

Notice that you can make the code more crisp, but then you lose the ability to crosscheck intermediate steps and are more likely to blame TikZ if it goes wrong. Anyway, here is a more crisp variant.

\documentclass{article}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}

\draw[color=lightgray] (8,0) grid [step=4]  (16,8);

\foreach \n in {8,12,16}
\node [below] at (\n,0) {$\n$};

\foreach \s in {0,4,8}
\node [left] at (8,\s) {$\s$};

\def\elts{%
{{14,6,3,3}},%     %% Should produce a dot at (14,6), not at (13,5) 
{{16,4,15,8}},%    %% Try changing the 15 to a 7 for puzzlement.
{{14,2,100,1}}%    %% (14,2) as intended
}

\foreach \e in \elts
{
\draw [fill] ({\e[0]},{\e[1]}) circle [radius=0.05];
}
\end{tikzpicture}
\end{document}
  • 1
    I don't think it's tikz's fault, but arguably it might be latex's fault for having weird rules for braces. It's frustrating that a macro cannot tell whether an argument used to be braced or not, which is problem that \foreach is having. Without this issue, the behavior would be much more intuitive. – Hood Chatham Nov 20 '18 at 0:43
  • @HoodChatham I did not claim it is TikZ' fault. (What's the purpose of the {} at the end of \draw [fill] (\e[0],\e[1]) circle [radius=0.05] {}; in your answer?) – user121799 Nov 20 '18 at 0:50
  • 1
    @HoodChatham The issue is that in this context the braces serve two different purposes: they are delimiters of groups (since after all this is TeX) and lists (or arrays). And yes, this is confusing. Therefore I'd like to argue that it is advantageous to proceed in small steps, and also put \typeouts to double-check that at each step one really has what one wants to. Related to that, I personally prefer to add TeX groups whenever the parser is to be activated, which explains ({\e[0]},{\e[1]}) which is not absolutely necessary here. – user121799 Nov 20 '18 at 1:01
  • 1
    Yeah, perhaps it would have been better if tikz had used some other delimiter for lists. Though I guess () and [] are also taken and <> is a pretty counter-intuitive choice. The extra {} at the end was an accident, not sure how it got there. – Hood Chatham Nov 20 '18 at 1:16
3

The new lines in your macro \elts lead to spaces, as usual in tex. Every line except for the last ends in a comma and \foreach automatically eats initial spaces in entries, but the final new line adds a trailing space to the entry. Add a % to suppress this space.

When the entire argument of a macro is braced, tex strips the braces, so the braces around each list get stripped so you need to add back in a pair of braces. (The reason we were concerned about the trailing space is that that trailing space in the last entry prevents tex from remove the braces from the last entry leading to inconsistent bracing).

\documentclass{article}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}

\draw[color=lightgray] (8,0) grid [step=4]  (16,8);

\foreach \n in {8,12,16}
\node [below] at (\n,0) {$\n$};

\foreach \s in {0,4,8}
\node [left] at (8,\s) {$\s$};

\def\elts{
{8,0},
{14,6,3,3},
{16,4,7,8},
{14,2,100,1}% Prevent terminal space so the braces from last entry aren't stripped
}

\foreach\e in \elts
\draw [fill] ({\e}[0],{\e}[1]) % Put the stripped braces back
      circle [radius=0.05];

\end{tikzpicture}
\end{document} 

An alternate construction that works is to ensure that every entry has a trailing space so that tex doesn't remove the braces around your coordinates to begin with:

\documentclass{article}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}

\draw[color=lightgray] (8,0) grid [step=4]  (16,8);

\foreach \n in {8,12,16}
\node [below] at (\n,0) {$\n$};

\foreach \s in {0,4,8}
\node [left] at (8,\s) {$\s$};

% There is a space after each entry which prevents tex from removing
% any braces.
\def\elts{
{8,0} ,
{14,6,3,3} ,     %% Should produce a dot at (14,6), not at (13,5)
{16,4,7,8} ,    %% Try changing the 15 to a 7 for puzzlement.
{14,2,100,1}    %% (14,2) as intended
}

\foreach\e in \elts
% No need to replace the braces because they didn't get removed in the first place
\draw [fill] (\e[0],\e[1]) 
    circle [radius=0.05];

\end{tikzpicture}
\end{document} 

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.