[Tex/LaTex] Refer to a node in tikz that will be defined “in the future” (two passes)

cross-referencingtikz-pgftikzmark

I have devised a small couple of commands to have a nice "callout thing" for my notes; please consider the following MWE (the problem is also explained there):

\documentclass{book}
\usepackage{tikz}
\tikzset{remember picture, 
    round mark/.style={
    circle, draw=yellow, minimum size=5mm, fill opacity=0.5, fill=yellow,
    },
}
\usepackage{pgfplots}\pgfplotsset{compat=1.9} 

\usepackage{siunitx}
\DeclareSIUnit{\krypt}{\ensuremath{\mathcal{K}r}}

\usepackage{xparse}
\newcommand{\roundmark}[1]{\tikz[overlay, remember picture, baseline=-0.5ex]
    \node [round mark, anchor=west] (#1) {};}
\NewDocumentCommand \addline {O{} m m }{%
    \begin{tikzpicture}[overlay,remember picture]
        \draw[ultra thick, yellow, ->, #1 ] (expl@#2) -- (#3);
    \end{tikzpicture}%
}
\NewDocumentCommand \margincallout {O{} m +m }{%
    \marginpar{
    \begin{tikzpicture}[overlay,remember picture]
        \node [ anchor=west, draw=orange, fill=yellow!20,  
            text width=\marginparwidth, align=left, font=\small, 
            #1 ] (expl@#2)
            at (0,0) {
                #3
            }; 
        \draw[ultra thick, yellow,->] (expl@#2) -- (#2);
\end{tikzpicture}}%
}

\begin{document}

I can mark thing in \roundmark{a}the main text and then have nice callouts from the marginpar to this point. 
\margincallout{a}{This is a callout, a nice one and it's ok.}

% thanks @bloodworks http://tex.stackexchange.com/a/62285/38080
% require package capt-of
\begin{figure}[htb]
        \begin{center}
            \begin{tikzpicture}[remember picture,
                ]
                \begin{axis}[
                        width=7cm,
                        xmin=0, xmax=10, domain=0:10,
                        enlarge y limits = 0.2,
                        ylabel = {Sensor R (\si{k\ohm})},
                        xlabel = {Kryporad (\si{\krypt})},
                        legend pos = north west, 
                        legend style={nodes=right},
                    ]
                    \addplot[red] {134 + 18.5*x + 15.0*sin(deg(0.664*x))};
                    \addplot[blue, dashed] {143 + 16.8*x};
                    \legend{non-linear fit, linear fit}
                \end{axis}
                \node [round mark] (hor-axis) at (4,-0.5) {}; 
                \node [round mark] (ver-axis) at (-0.5,4) {}; 
                %\draw (0,0) grid (5,5);
            \end{tikzpicture}
        \end{center}

        \caption{With a bit of guesswork I can mark things in the graphics, too}
        \label{fig:calibR}
\end{figure}
\margincallout[yshift=3cm]{hor-axis}{\textbf{Always} name the axis and columns, and use units when needed}
\addline{hor-axis}{ver-axis}

Uncomment the following to see the error: 


%But if I want to put the callout \textbf{before} the mark, 
%as in \margincallout{future}{A forward callout} it will not work, and give me an error. 

%The mark will be \roundmark{future}here, for example. 

\end{document}

which outputs a nice (IMHO) thing:

Result of the MWE

The problem is that sometime it is useful to have the \margincallout command before the \roundmark that defines the node name.

The document will require two pass anyway; I was thinking that maybe is possible to write something like the forward references for label… but I can't find any solution.

Is it possible to refer to nodes that will be resolved in the next pass?

UPDATE:

So I tried with tikzmark, but there must be something going strange here.
Look:

\documentclass{book}
\usepackage{tikz}
\usetikzlibrary{tikzmark}
\tikzset{remember picture, 
    round mark/.style={
    circle, draw=yellow, minimum size=5mm, fill opacity=0.5, fill=yellow,
    },
}
\usepackage{pgfplots}\pgfplotsset{compat=1.9} 

\usepackage{siunitx}
\DeclareSIUnit{\krypt}{\ensuremath{\mathcal{K}r}}

\usepackage{xparse}
\newcommand{\rtikzmark}[1]{\tikzmark[{
    \node [baseline=-0.5ex, round mark, anchor=west]{}}]{#1}}
\NewDocumentCommand \addline {O{} m m }{%
    \begin{tikzpicture}[overlay,remember picture]
        \draw[ultra thick, yellow, ->, #1 ] (expl@#2) -- (pic  cs:#3);
    \end{tikzpicture}%
}
\NewDocumentCommand \margincallout {O{} m +m }{%
    \marginpar{
    \begin{tikzpicture}[overlay,remember picture]
        \node [ anchor=west, draw=orange, fill=yellow!20,  
            text width=\marginparwidth, align=left, font=\small, 
            #1 ] (expl@#2)
            at (0,0) {
                #3
            }; 
        \draw[ultra thick, yellow,->] (expl@#2) -- (pic cs: #2); 
\end{tikzpicture}}%
}

\begin{document}

I can mark thing in \rtikzmark{a}the main text and then have nice callouts from the marginpar to this point. 
\margincallout{a}{This is a callout, a nice one and it's ok.}

% thanks @bloodworks http://tex.stackexchange.com/a/62285/38080
% require package capt-of
\begin{figure}[htb]
        \begin{center}
            \begin{tikzpicture}[remember picture,
                ]
                \begin{axis}[
                        width=7cm,
                        xmin=0, xmax=10, domain=0:10,
                        enlarge y limits = 0.2,
                        ylabel = {Sensor R (\si{k\ohm})},
                        xlabel = {Kryporad (\si{\krypt})},
                        legend pos = north west, 
                        legend style={nodes=right},
                    ]
                    \addplot[red] {134 + 18.5*x + 15.0*sin(deg(0.664*x))};
                    \addplot[blue, dashed] {143 + 16.8*x};
                    \legend{non-linear fit, linear fit}
                \end{axis}
                \node [round mark] at (4,-0.5) {}; \tikzmark{hor-axis};
                \node [round mark] at (-0.5,4) {}; \tikzmark{ver-axis};
                %\draw (0,0) grid (5,5);
            \end{tikzpicture}
        \end{center}

        \caption{With a bit of guesswork I can mark things in the graphics, too}
        \label{fig:calibR}
\end{figure}
\margincallout[yshift=3cm]{hor-axis}{\textbf{Always} name the axis and columns, and use units when needed}
\addline{hor-axis}{ver-axis}

Uncomment the following to see the error: 


But if I want to put the callout \textbf{before} the mark, 
as in \margincallout{future}{A forward callout} it will not work, and give me an error. 

The mark will be \rtikzmark{future}here, for example. 

\end{document}

The first call (in-text) sort of work, but then the line is not drawn. And the second and third call (the one marking points into the graph) transform the whole figure in overlay…

Ach...

The good thing is that the forward callout does work, but the line is not drawn. Puzzled.

Best Answer

(I'm adding this above because it supersedes the original answer and so someone looking for just the what and not bothered about the how, when, and certainly not the why shouldn't bother to read the original answer.)

Stop Press: tikzmark evolves again

tikzmark has undergone considerable evolution since its first inception, primarily driven by questions on this site. One of the key features it picked up along the way was the ability for the coordinate it saved to be used prior to its occurrence in the document.

One of its attributes that it has had from the start was that it was intended to be used outside a \tikz command or tikzpicture environment. Inside, the thinking was, then one has full access to TikZ's normal coordinate remembering service and so there was no need for a \tikzmark.

However, the aforementioned key feature is not something that TikZ provides. There isn't a way to refer to a coordinate inside a tikzpicture prior to its declaration. So if one wants to do that, one needs something new.

The key feature of this question is that the querent wants to use the same mechanism to refer to coordinates inside a tikzpicture as outside it. So that suggests that the correct way to provide this clairvoyance coordinate capability inside tikzpictures is to extend the tikzmark.

This turned out to be quite easy. In short, what tikzmark does is to associate a label with the origin of a tikzpicture and all the heavy lifting is done in the coordinate system stuff. The extension is to add in a potential offset, so that once tikz has worked out where on the page the origin of said tikzpicture is then it applies the offset. Combine that with a test to see if we're inside a tikzpicture, and all's done.

(Worth noting that if you switch to this new version, you should delete the aux file before recompiling otherwise you'll get lots of errors on the first recompile.)

The syntax inside a tikzpicture is \tikzmark{label}{coordinate}, eg \tikmark{a}{(3,4)}. This means that the coordinate (pic cs:a) will point to the point (3,4) in the current picture.

You can download this new version of tikzmark from github: download tikzmark.dtx and run tex tikzmark.dtx to generate the files.

So with the new, improved \tikzmark, the code is now back to a reasonable state once more:

\documentclass{book}
%\url{http://tex.stackexchange.com/q/295903/86}
\usepackage{tikz}
\usetikzlibrary{tikzmark}
\tikzset{remember picture, 
    round mark/.style={
    circle, draw=yellow, minimum size=5mm, fill opacity=0.5, fill=yellow,
    },
}
\usepackage{pgfplots}\pgfplotsset{compat=1.9} 

\usepackage{siunitx}
\DeclareSIUnit{\krypt}{\ensuremath{\mathcal{K}r}}

\usepackage{xparse}
\newcommand{\rtikzmark}[1]{\tikzmark[{
    \node [baseline=-0.5ex, round mark, anchor=west]{}}]{#1}}
\NewDocumentCommand \addline {O{} m m }{%
    \begin{tikzpicture}[overlay,remember picture]
        \draw[ultra thick, yellow, ->, #1 ] (expl@#2) -- (pic cs:#3);
    \end{tikzpicture}%
}

\NewDocumentCommand \margincallout {O{} m +m }{%
    \marginpar{
    \begin{tikzpicture}[overlay,remember picture]
        \node [ anchor=west, draw=orange, fill=yellow!20,  
            text width=\marginparwidth, align=left, font=\small, 
            #1 ] (expl@#2)
            at (0,0) {
                #3
            }; 
        \draw[ultra thick, yellow,->] (expl@#2) -- (pic cs:#2); 
\end{tikzpicture}}%
}

\begin{document}

I can mark thing in \rtikzmark{a}the main text and then have nice callouts from the marginpar to this point. 
\margincallout{a}{This is a callout, a nice one and it's ok.}

% thanks @bloodworks http://tex.stackexchange.com/a/62285/38080
% require package capt-of
\begin{figure}[htb]
        \begin{center}
            \begin{tikzpicture}[remember picture,
                ]
                \begin{axis}[
                        width=7cm,
                        xmin=0, xmax=10, domain=0:10,
                        enlarge y limits = 0.2,
                        ylabel = {Sensor R (\si{k\ohm})},
                        xlabel = {Kryporad (\si{\krypt})},
                        legend pos = north west, 
                        legend style={nodes=right},
                    ]
                    \addplot[red] {134 + 18.5*x + 15.0*sin(deg(0.664*x))};
                    \addplot[blue, dashed] {143 + 16.8*x};
                    \legend{non-linear fit, linear fit}
                \end{axis}
                \node [round mark] at (4,-0.5) (hor-axis) {};
                \node [round mark] at (-0.5,4) (ver-axis) {};
                \node [round mark] at (0,0) (origin) {};
                \tikzmark{hor-axis}{(hor-axis)}
                \tikzmark{ver-axis}{(ver-axis)}
                \tikzmark{origin}{(origin)}
                %\draw (0,0) grid (5,5);
            \end{tikzpicture}
        \end{center}

        \caption{With a bit of guesswork I can mark things in the graphics, too}
        \label{fig:calibR}
\end{figure}
\margincallout[yshift=4cm]{hor-axis}{\textbf{Always} name the axis and columns, and use units when needed}
\addline{hor-axis}{ver-axis}
\addline{hor-axis}{origin}

Uncomment the following to see the error: 


But if I want to put the callout \textbf{before} the mark, 
as in \margincallout{future}{A forward callout} it will not work, and give me an error. 

The mark will be \rtikzmark{future}here, for example. 

\end{document}

(Same image as below)


Original Answer Follows:

A few things here ...

(Firstly, I found a bug in tikzmark in its interaction with marginpar. I have a suspicion that the version with the bug is newer than the version on CTAN since you shouldn't have gotten anything in your second example if you were using the buggy version. Anyway, an updated version is available on github.)

Secondly, and more importantly, \tikzmark is not designed to be used inside a tikzpicture environment. Things Go Wrong if you do. It's even more serious than using regex to parse HTML. The point is that if you're inside a tikzpicture environment then you have access to all the node and coordinate positioning stuff of tikz and don't need tikzmark.

(Mind you, it doesn't seem to matter how many times I say "Don't use tikzmark inside a tikzpicture", folk seem to want to use it. Maybe I should bite the bullet and figure out how to make it work.)

Admittedly, that means you need two versions of your callout code: one for when the mark is in a tikzpicture and one when it isn't. There are probably snazzy ways to code this to avoid that, but I'm a bear of little brain and can't think that expansively at this hour.

So although this will never win in a style contest, here's a working version of your code with what I think should be the right outcome.

\documentclass{book}
%\url{http://tex.stackexchange.com/q/295903/86}
\usepackage{tikz}
\usetikzlibrary{tikzmark}
\tikzset{remember picture, 
    round mark/.style={
    circle, draw=yellow, minimum size=5mm, fill opacity=0.5, fill=yellow,
    },
}
\usepackage{pgfplots}\pgfplotsset{compat=1.9} 

\usepackage{siunitx}
\DeclareSIUnit{\krypt}{\ensuremath{\mathcal{K}r}}

\usepackage{xparse}
\newcommand{\rtikzmark}[1]{\tikzmark[{
    \node [baseline=-0.5ex, round mark, anchor=west]{}}]{#1}}
\NewDocumentCommand \addline {O{} m m }{%
    \begin{tikzpicture}[overlay,remember picture]
        \draw[ultra thick, yellow, ->, #1 ] (expl@#2) -- (pic cs:#3);
    \end{tikzpicture}%
}

\NewDocumentCommand \addlineb {O{} m m }{%
    \begin{tikzpicture}[overlay,remember picture]
        \draw[ultra thick, yellow, ->, #1 ] (expl@#2) -- (#3);
    \end{tikzpicture}%
}


\NewDocumentCommand \margincallout {O{} m +m }{%
    \marginpar{
    \begin{tikzpicture}[overlay,remember picture]
        \node [ anchor=west, draw=orange, fill=yellow!20,  
            text width=\marginparwidth, align=left, font=\small, 
            #1 ] (expl@#2)
            at (0,0) {
                #3
            }; 
        \draw[ultra thick, yellow,->] (expl@#2) -- (pic cs:#2); 
\end{tikzpicture}}%
}

\NewDocumentCommand \margincalloutb {O{} m +m }{%
    \marginpar{
    \begin{tikzpicture}[overlay,remember picture]
        \node [ anchor=west, draw=orange, fill=yellow!20,  
            text width=\marginparwidth, align=left, font=\small, 
            #1 ] (expl@#2)
            at (0,0) {
                #3
            }; 
        \draw[ultra thick, yellow,->] (expl@#2) -- (#2); 
\end{tikzpicture}}%
}

\begin{document}

I can mark thing in \rtikzmark{a}the main text and then have nice callouts from the marginpar to this point. 
\margincallout{a}{This is a callout, a nice one and it's ok.}

% thanks @bloodworks http://tex.stackexchange.com/a/62285/38080
% require package capt-of
\begin{figure}[htb]
        \begin{center}
            \begin{tikzpicture}[remember picture,
                ]
                \begin{axis}[
                        width=7cm,
                        xmin=0, xmax=10, domain=0:10,
                        enlarge y limits = 0.2,
                        ylabel = {Sensor R (\si{k\ohm})},
                        xlabel = {Kryporad (\si{\krypt})},
                        legend pos = north west, 
                        legend style={nodes=right},
                    ]
                    \addplot[red] {134 + 18.5*x + 15.0*sin(deg(0.664*x))};
                    \addplot[blue, dashed] {143 + 16.8*x};
                    \legend{non-linear fit, linear fit}
                \end{axis}
                \node [round mark] at (4,-0.5) (hor-axis) {};
                \node [round mark] at (-0.5,4) (ver-axis) {};
                \node [round mark] at (0,0) (origin) {};
                %\draw (0,0) grid (5,5);
            \end{tikzpicture}
        \end{center}

        \caption{With a bit of guesswork I can mark things in the graphics, too}
        \label{fig:calibR}
\end{figure}
\margincalloutb[yshift=4cm]{hor-axis}{\textbf{Always} name the axis and columns, and use units when needed}
\addlineb{hor-axis}{ver-axis}
\addlineb{hor-axis}{origin}

Uncomment the following to see the error: 


But if I want to put the callout \textbf{before} the mark, 
as in \margincallout{future}{A forward callout} it will not work, and give me an error. 

The mark will be \rtikzmark{future}here, for example. 

\end{document}

callouts and tikzmark