3

Can someone help me understand why in the two calls to mydraw, the addplot is executed twice, but the draw is only executed once? I see the "dot" created by both addplots, but only the label for the second draw. Note that commenting out the second \mydraw causes the first one to be drawn correctly.

\documentclass{minimal}

\usepackage{pgfplots}
\usepackage{pgfkeys}
\usepackage{tikz}

\newcommand{\setValue}[1]{\pgfkeys{/variables/#1}}
\newcommand{\getValue}[1]{\pgfkeysvalueof{/variables/#1}}
\newcommand{\declare}[1]{%
 \pgfkeys{
  /variables/#1.is family,
  /variables/#1.unknown/.style = {\pgfkeyscurrentpath/\pgfkeyscurrentname/.initial = ##1}
 }%
}

\declare{}

\newcommand{\mydraw}[1]{%

  \declare{test/}
  \setValue{test, value = #1}

  \addplot [mark=*] coordinates{(\getValue{test/value},0.3)};
  \draw node at (axis cs:\getValue{test/value},0.4) [below] {\getValue{test/value}}; 
}


\begin{document}

\begin{tikzpicture}
  \begin{axis}

    \addplot coordinates{(0,0) (1,1)};

    \mydraw{0.4}
    \mydraw{0.6}
    \end{axis}
\end{tikzpicture}

\end{document}

enter image description here

  • Why all the messing around with pgfkeys? You can pass #1 directly. – John Kormylo Jan 21 at 15:28
  • Yeah, but in complicated code with many arguments (I have things with up to 7), it can become difficult to understand/debug code that uses #1, #2, etc. As you can probably tell, I'm a C++ coder and want a way to name the inputs to make the code more understandable. I could also use \def to name the inputs, though this becomes tedious. – Christopher Donham Jan 21 at 19:16
7

This is because pgfplots has a survey phase, and a do-it-really phase. So your commands get executed, but not for real, so you overwrite the value. You can fix this with a trick that can be found on p. 543 of pgfplots manual v1.16.

\documentclass[tikz,border=3mm]{standalone}

\usepackage{pgfplots}

\newcommand{\setValue}[1]{\pgfkeys{/variables/#1}}
\newcommand{\getValue}[1]{\pgfkeysvalueof{/variables/#1}}
\newcommand{\declare}[1]{%
 \pgfkeys{
  /variables/#1.is family,
  /variables/#1.unknown/.style = {\pgfkeyscurrentpath/\pgfkeyscurrentname/.initial = ##1}
 }%
}

\declare{}

\newcommand{\mydraw}[1]{%
  \declare{test/}
  \setValue{test, value = #1}
  \edef\temp{
  \noexpand\addplot [mark=*] coordinates{(\getValue{test/value},0.3)};
  \noexpand\draw node at (axis cs:\getValue{test/value},0.4) [below] {\getValue{test/value}}; 
  }
  \temp
}


\begin{document}

\begin{tikzpicture}
  \begin{axis}

    \addplot coordinates{(0,0) (1,1)};

    \mydraw{0.4}
    \mydraw{0.6}
    \end{axis}
\end{tikzpicture}

\end{document}

enter image description here

  • Needless to say that you could get the result much more conveniently with nodes near coords. This answer assumes that you ask about expansion issues, and are not interested in such solutions for now. – Schrödinger's cat Jan 21 at 5:22
  • Actually, after seeing your solution/text, I will go RTFM about the "survey phase". In the mean time, this leads to the question you suggest above. As a practical matter, the way to solve the problem is to remove tikz commands and use only pgfplots commands? (I did not know that mixing them was a problem) – Christopher Donham Jan 21 at 12:09
  • @ChristopherDonham It is not necessarily a distinction between \addplot and tikz commands. The question is more whether or not the arguments are expanded. If you do \addplots in a \foreach loop, you very likely will need this trick as well. – Schrödinger's cat Jan 21 at 15:37
  • What would you suggest as the best way to solve the issue? Your comment earlier suggests that the code you wrote illustrated the problem (thank you), but you had other solutions in mind. – Christopher Donham Jan 21 at 19:13
  • 1
    @ChristopherDonham You get the same output with \addplot[nodes near coords,only marks,mark=*,point meta=x, nodes near coords style={anchor=south}] coordinates{(0.4,0.3) (0.6,0.3)};. – Schrödinger's cat Jan 21 at 19:20
1

The problem isn't \draw, the problem is that \SetValue has to be run twice.

\documentclass{standalone}
\usepackage{pgfplots}

\newcommand{\setValue}[1]{\pgfkeys{/variables/#1}}
\newcommand{\getValue}[1]{\pgfkeysvalueof{/variables/#1}}
\newcommand{\declare}[1]{%
 \pgfkeys{
  /variables/#1.is family,
  /variables/#1.unknown/.style = {\pgfkeyscurrentpath/\pgfkeyscurrentname/.initial = ##1}
 }%
}

\declare{}

\newcommand{\mydraw}[1]{%

  \declare{test/}
  \setValue{test, value = #1}
  \pgfplotsextra{\setValue{test, value = #1}}

  \addplot [mark=*] coordinates{(\getValue{test/value},0.3)};
  \draw node at (axis cs:\getValue{test/value},0.4) [below] {\getValue{test/value}}; 
}


\begin{document}

\begin{tikzpicture}
  \begin{axis}

    \addplot coordinates{(0,0) (1,1)};

    \mydraw{0.4}
    \mydraw{0.6}
    \end{axis}
\end{tikzpicture}

\end{document}
  • I'm not sure I understand. The \addplot is clearly seeing the two different values for test/value, so it seems that the \setValue must be executed twice. In fact, I originally had thought that the issue was that the \draw was somehow delayed in execution so that the second \setValue is overwriting the first before the \draw is completed. In the solution you are proposing, if I have 3x \mydraw, do I need multiple \pgfplotsextra statements? How do I know how many I need? – Christopher Donham Jan 21 at 19:21
  • 1
    \pgfplotsextra delays the call until the do-it phase. Older versions required \pgfplotsextra for \draw as well, but the newer versions don't (at least when using axis cs:). I believe \addplot stores the data internally for later use. – John Kormylo Jan 21 at 23:10

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.