2

Here's something mystifying: I've been trying to use a for loop to create several copies of essentially the same picture stacked vertically on top of one another. But when I use \pgfmathresult in the yshift value, it puts all copies of the picture in the same spot - essentially it acts as if \pgfmathresult evaluates to 0 regardless of what the actual result of the computation is. It's probably best illustrated by this MWE:

\documentclass{article}
\usepackage{tikz}

\begin{document}
  \begin{tikzpicture}
    \foreach \i in {1,...,4} {
      \pgfmathparse{2*\i}
      \begin{scope}[yshift=\pgfmathresult cm]
        \fill (0,0) circle(3pt);
      \end{scope}
    }
  \end{tikzpicture}
\end{document}

The weird thing is that if I change yshift to xshift, the copies of the picture are spread out horizontally as I would expect. Is there some reason for this behavior, or is it a bug?

Caramdir
  • 89,023
  • 26
  • 255
  • 291
David Z
  • 12,084
  • 7
  • 48
  • 65
  • This is likely the same problem as, for example, here: http://tex.stackexchange.com/questions/9988/tikz-pgfmathresult-problem-inside-angle-pgfmathresult-coordinate or http://tex.stackexchange.com/questions/10258/drawing-a-chord-net-with-tikz. – Caramdir Mar 08 '11 at 04:22
  • Side remark: you should be able to just write [yshift=2*\i cm]. – Caramdir Mar 08 '11 at 04:24
  • @Caramdir: okay, I didn't recognize either of those as the same problem. I thought the fact that it worked with xshift but not yshift suggested some deeper explanation. – David Z Mar 08 '11 at 04:51
  • And re: the side remark, the actual calculation is going to be something like 75*(\i - 1) pt, which doesn't work when I put it directly in yshift. – David Z Mar 08 '11 at 04:53
  • @David: Yes you are right but It's preferable to never use \pgfmathresultdirectly. I think it's a good way to avoid this and in this case you have three solutions : you can avoid the use of a scope and the use of pgfmathresult, you can use shift and not yshift like Frédéric or you can use \pgfmathsetmacro – Alain Matthes Mar 08 '11 at 05:01
  • @David: with 75*(\i-1)pt you can avoid the scope and use \myshiftlike in my answer \draw[yshift=\myshift pt,fill] (0,0) circle(3pt); – Alain Matthes Mar 08 '11 at 05:12
  • @Altermundus: yes, I did see your answer, thanks. I just wanted to point out that putting the mathematical expression itself directly as the value in yshift= is not a solution that works for me. – David Z Mar 08 '11 at 05:29
  • @David: try yshift={(75*(\i - 1))*1pt} – Caramdir Mar 08 '11 at 05:57
  • @Caramdir: ah, sneaky... thanks for pointing that out. – David Z Mar 08 '11 at 20:13

2 Answers2

6

The better solution is :

\documentclass{article}
\usepackage{tikz}

\begin{document}
  \begin{tikzpicture}
    \foreach \i in {1,...,4} {
        \draw[yshift=2*\i cm,fill] (0,0) circle(3pt);
    }
  \end{tikzpicture}
\end{document}

but

It's always a good way to stock the \pgfmathresult in a personal macro or to use \pgfmathsetmacro

\documentclass{article}
\usepackage{tikz}

\begin{document}
  \begin{tikzpicture}
    \foreach \i in {1,...,4} {
      %\pgfmathparse{2*\i}
      \pgfmathsetmacro{\myshift}{2*\i} 
      \begin{scope}[yshift=\myshift cm]
        \fill (0,0) circle(3pt);
      \end{scope}
    }
  \end{tikzpicture}
\end{document} 

now with 75*(\i - 1), Caramdir's remark is fine, we can use 75*(\i - 1)*1pt

\documentclass{article}
\usepackage{tikz}    
\begin{document}
  \begin{tikzpicture}
    \foreach \i in {1,...,4} {
        \draw[yshift=75*(\i - 1)* 1 pt,fill] (0,0) circle(3pt);
    }
  \end{tikzpicture}      
\end{document} 
Alain Matthes
  • 95,075
2

I find that using shift={(x,y)}]is less prone to unwanted effects (I don't know why this is). In your case, you should write

\documentclass{article}
\usepackage{tikz}

\begin{document}
  \begin{tikzpicture}
    \foreach \i in {1,...,4} {
      \pgfmathparse{2*\i}
      \begin{scope}[shift={(0,\pgfmathresult)}]
        \fill (0,0) circle(3pt);
      \end{scope}
    }
  \end{tikzpicture}
\end{document}

The result is then exactly what you are looking for :

enter image description here

Frédéric
  • 11,087
  • 3
  • 37
  • 43
  • The shift={(x,y)} is more "stable" because it reads the value as coordinate which is then parsed, but xshift and yshift await a simple dimension. In the first case you can use numbers without units. – Martin Scharrer Mar 08 '11 at 08:21