# [Tex/LaTex] Node position with \addplot

pgfplotstikz-pgf

I don't understand why the blue "Below" label does not appear right below the "Above" label (near the expected position showed by the red "Below" label). Any idea?

\documentclass{standalone}
\usepackage{pgfplots}
\begin{document}
\begin{tikzpicture}
\begin{axis}
node[draw, pos = .5] (A) {}
node[above, sloped, pos = .5] {Above}
node[below, sloped, pos = .5] {Below};
\node[rotate = 45, anchor = north, font = \color{red}] at (A.south east) {Below};
\end{axis}
\end{tikzpicture}
\end{document}


Here is why:

In TikZ, the pos=.5 option is handled by \tikz@timer with the argument stored in \tikz@time. The pgfplots package redefined this macro by

pgfplotscoordprocessing.code.tex

8178    \let\tikz@timer=\pgfplots@plot@timer%

7809    \def\pgfplots@plot@timer{%
7810        \pgfplotstransformplotattime{\tikz@time}%
7811    }

7819    \def\pgfplotstransformplotattime#1{%
7820      \pgftransformshift{\pgfplotspointplotattime{#1}}%
7821      \ifpgfresetnontranslationattime%
7822        \pgftransformresetnontranslations%
7823      \fi%
7824      \ifpgfslopedattime%
7825     \pgfplotsplothandlertransformslopedattime{#1}{\pgfplotspointplotattimefirst}{\pgfplotspointplotattimesecond}%
7826     \fi%
7827    }


In this question, nodes are not positioned properly. So we now focus on line 7820.

Recall that \pgftransformshift is a macro with one argument. The argument will be executed first and (usually) it will calculate \pgf@x and \pgf@y. And then PGF will shift (\pgf@x,\pgf@y). (see also the manual and pgfcoretransformations.code.tex)

In other words, \pgfplotspointplotattime{#1} should setup \pgf@x and \pgf@y properly. Here is (ideally) how \pgfplotspointplotattime should work:

• if this \tikz@time is used before, reuse the calculated values.
• If not, calculate values and cache them.

And here is ideally how your code will be processed

• node[draw, pos = .5] (A) {} --> new \tikz@time, calculate everything and cache them.
• node[above, sloped, pos = .5] {Above} --> same \tikz@time, reuse.
• node[below, sloped, pos = .5] {Below} --> same \tikz@time, reuse.

It turns out that when \tikz@time is not new, pgfplots does not setup \pgf@x and \pgf@y properly. The fact that the Above node is placed correctly is pure luck --- no one changes the values of \pgf@x and \pgf@y so it is placed in the same place. However the values are changed when the Above node is typeset, therefore the Before node is not placed correctly.

The following example back-ups the observation above.

\documentclass[tikz]{standalone}
\usepackage{pgfplots}
\pgfplotsset{compat=1.14}
\begin{document}
\begin{tikzpicture}
\begin{axis}
node[pos=.3]{.3 new value}
node[pos=.7]{.7 new value}
node[pos=.3]{.3 should reuse}
;
\end{axis}
\end{tikzpicture}
\end{document}


The following example, on the other hand, shows that pgfplots does cache other information such as slope.

\documentclass[tikz]{standalone}
\usepackage{pgfplots}
\pgfplotsset{compat=1.14}
\begin{document}
\begin{tikzpicture}
\begin{axis}
node[pos=.3,sloped]{.3 new value}
node[pos=.7,sloped]{.7 new value}
node[pos=.3,sloped]{.3 should reuse}
;
\end{axis}
\end{tikzpicture}
\end{document}


To fix this problem, one may try pos=.49999 to force pgfplots to recalculate everything. Or one might change the definition of \pgfplotspointplotattimeaddtocache to

\def\pgfplotspointplotattimeaddtocache#1{%
\ifnum\pgfplotspointplotattime@cachesize=\pgfplotspointplotattime@cachesize@max
\pgfplotspointplotattimeclearcache
\fi
\pgf@xa=#1pt %
\edef\pgfplots@loc@TMPa{%
\noexpand\gdef\noexpand\pgfplotspointplotattimefirst{\pgfplotspointplotattimefirst}%
\noexpand\gdef\noexpand\pgfplotspointplotattimesecond{\pgfplotspointplotattimesecond}%
\noexpand\gdef\noexpand\pgfplotspointplotattimecoords{\pgfplotspointplotattimecoords}%
}%
\t@pgfplots@toka=\expandafter{\pgfplotspointplotattime@cache}%
\t@pgfplots@tokb=\expandafter{\pgfplots@loc@TMPa}%
\xdef\pgfplotspointplotattime@cache{%
\the\t@pgfplots@toka
\noexpand\pgfkeyssetvalue{/data point/@pos \the\pgf@xa/segment \pgfkeysvalueof{/tikz/pos segment}}{\the\t@pgfplots@tokb}%
}%
}


so that it will remember the position.

# MWE

\documentclass[tikz]{standalone}
\usepackage{pgfplots}
\pgfplotsset{compat=1.14}
\begin{document}

\makeatletter
\ifnum\pgfplotspointplotattime@cachesize=\pgfplotspointplotattime@cachesize@max
\pgfplotspointplotattimeclearcache
\fi
\pgf@xa=#1pt %
\edef\pgfplots@loc@TMPa{%
\noexpand\gdef\noexpand\pgfplotspointplotattimefirst{\pgfplotspointplotattimefirst}%
\noexpand\gdef\noexpand\pgfplotspointplotattimesecond{\pgfplotspointplotattimesecond}%
\noexpand\gdef\noexpand\pgfplotspointplotattimecoords{\pgfplotspointplotattimecoords}%
}%
\t@pgfplots@toka=\expandafter{\pgfplotspointplotattime@cache}%
\t@pgfplots@tokb=\expandafter{\pgfplots@loc@TMPa}%
\xdef\pgfplotspointplotattime@cache{%
\the\t@pgfplots@toka
\noexpand\pgfkeyssetvalue{/data point/@pos \the\pgf@xa/segment \pgfkeysvalueof{/tikz/pos segment}}{\the\t@pgfplots@tokb}%
}%
}
\begin{tikzpicture}
\begin{axis}