Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

I'm trying to come up with a solution to the question How to maintain consistency with TikZ and Pgfplots?. Essentially, what is needed is a way to save a coordinate as a macro (or a global key, maybe?) that can then be used instead of the usual <x>,<y> pair, both in normal nodes/paths and in pgfplots plots.

For clarification: I would like to be able to define a macro \PointA that I can call whenever the syntax (<x>,<y>) is expected. This might be in the definition of a node using \node at (<x>,<y>) {};, or in a pgfplots plot using \addplot coordinates { (0,0) (<x>,<y>) (1,1) };

Just using \def\<name>{<x>,<y>} works fine for normal nodes and paths, but when I try to use it as a coordinate in a pgfplots plot, it fails with the error message:

File ended while scanning use of \pgfplots@foreach@plot@coord@NEXT.

An expansion issue, yet again? Or should I use a totally different approach?

\documentclass{article}
\usepackage{pgfplots}

\def\PointA{1,2}

\begin{document}
\begin{tikzpicture}

  \draw [gray] (0,0) grid (3,3);
  \fill (\PointA) circle (2pt); % Works

  \begin{axis}[xshift=3.5cm,width=6cm,xmin=0,xmax=3,ymin=0,ymax=3,grid=both]

    \fill [orange] (axis cs:\PointA) circle (4pt); % Works
    \addplot coordinates { (0,0) (1,2) (2,2) }; % Works
%    \addplot coordinates { (0,0) (\PointA) (2,2) }; % Fails

  \end{axis}
\end{tikzpicture}
\end{document}
share|improve this question

3 Answers 3

up vote 6 down vote accepted
+150

One way to achieve this is to patch the internal macro responsible of reading the coordinates. The \pgfplots@foreach@plot@coord@NEXT in pgfplotscoordprocessing.code.tex is called after the opening ( is detected and will read (#1,#2) from the input stream. In your example you have (\PointA) (2,2), so \PointA) (2 is taken as X and 2 as Y part. The idea is to patch this macro to expand the next token following ( to reveal the , in it. This can be done using the following code:

\documentclass{article}
\usepackage{pgfplots}

\def\PointA{1,2}

\makeatletter
\let\orig@pgfplots@foreach@plot@coord@NEXT\pgfplots@foreach@plot@coord@NEXT
\def\pgfplots@foreach@plot@coord@NEXT{%
    \expandafter\orig@pgfplots@foreach@plot@coord@NEXT\expandafter
}
\makeatother

\begin{document}
\begin{tikzpicture}

  \draw [gray] (0,0) grid (3,3);
  \fill (\PointA) circle (2pt); % Works

  \begin{axis}[xshift=3.5cm,width=6cm,xmin=0,xmax=3,ymin=0,ymax=3,grid=both]

    \fill [orange] (axis cs:\PointA) circle (4pt); % Works
%    \addplot coordinates { (0,0) (1,2) (2,2) }; % Works
    \addplot coordinates { (0,0) (\PointA) (2,2) }; % Works now!!

  \end{axis}
\end{tikzpicture}
\end{document}

Another method would be do patch the macro responsable to read the { } after coordinate to expanding that argument completely before processing it further. This has the benefit that you can include macros which hold several coordinates or other macros which wouldn't be expanded as well with the above code. The macro in question is called \pgfplots@addplotimpl@coordinates@ and reads the coordinates as #3. The following code expands that argument using \edef:

\documentclass{article}
\usepackage{pgfplots}

\def\PointA{1,2}

\def\mycoordinates{ (1,0) (2,1) (3,0) }

\makeatletter
\long\def\pgfplots@addplotimpl@coordinates@#1#2#3#4{%
    \pgfplots@start@plot@with@behavioroptions{#1,/pgfplots/.cd,#2}%
    \pgfplots@PREPARE@COORD@STREAM{#4}%
    \begingroup
    \edef\@tempa{{#3}}%
    \ifpgfplots@curplot@threedim
        \expandafter\endgroup\expandafter
        \pgfplots@coord@stream@foreach@threedim\@tempa
    \else
        \expandafter\endgroup\expandafter
        \pgfplots@coord@stream@foreach\@tempa
    \fi
}%
\makeatother

\begin{document}
\begin{tikzpicture}

  \draw [gray] (0,0) grid (3,3);
  \fill (\PointA) circle (2pt); % Works

  \begin{axis}[xshift=3.5cm,width=6cm,xmin=0,xmax=3,ymin=0,ymax=3,grid=both]

    \fill [orange] (axis cs:\PointA) circle (4pt); % Works
%    \addplot coordinates { (0,0) (1,2) (2,2) }; % Works
    \addplot coordinates { (0,0) (\PointA) (2,2) }; % Works now!!
    \addplot coordinates \mycoordinates; % Works as well!!
    \addplot coordinates { (0,1) \mycoordinates (6,7) }; % Works as well!!

  \end{axis}
\end{tikzpicture}
\end{document}

Alternatively you could define \PointAX and \PointAY and then write (\PointAX,\PointAY) which should also work without any patches.

share|improve this answer
    
That's great! Thanks a ton. You might want to post this approach also to this question: tex.stackexchange.com/questions/15684/… –  Jake Apr 18 '11 at 22:09
    
@Jake: I added a link back here to that question. Which of the two methods are you using / prefering? –  Martin Scharrer Apr 19 '11 at 10:59

You could store each coordinate separately or define a table:

\documentclass{article}
\usepackage{pgfplots}


\def\PointAx{1}
\def\PointAy{2}
\def\PointA{\PointAx,\PointAy}
\pgfplotstableread{%
  2 2
}{\PointB}

\begin{document}
\begin{tikzpicture}

  \draw [gray] (0,0) grid (3,3);
  \fill (\PointA) circle (2pt); % Works

  \begin{axis}[xshift=3.5cm,width=6cm,xmin=0,xmax=3,ymin=0,ymax=3,grid=both]

    \fill [orange] (axis cs:\PointA) circle (4pt); % Works
    \addplot coordinates { (1,2) }; % Works
    \addplot coordinates { (\PointAx,\PointAy) }; % Works
    \addplot table {\PointB}; % Works

  \end{axis}
\end{tikzpicture}
\end{document}
share|improve this answer
    
Storing the coordinate in a table is a good idea. However, this won't work in normal paths, but only in plots. I'm looking for a solution that will work in both. Sorry for not being clearer about that. I'll update the question. –  Jake Apr 15 '11 at 6:24

A different angle at looking at the issue:

\documentclass{article}
\usepackage{tikz}
\usepackage{pgfplots}

\def\PointA{1,2}
\def\PointB{coordinates {(3,3)}}
\begin{document}


\begin{tikzpicture}
  \draw [gray] (0,0) grid (3,3);
  \fill (\PointA) circle (2pt); % Works

  \begin{axis}[xshift=3.5cm,width=6cm,xmin=0,xmax=3,ymin=0,ymax=3,grid=both]
    \fill [orange] (axis cs:\PointA) circle (4pt); % Works
    \expandafter\addplot\PointB; % Works
  \end{axis}
\end{tikzpicture}
\end{document}

This is a simple and clean solution. Variations to it are possible. For example you can define a macro:

\def\Coordinates#1#2{%
  \def\A{#1}
  \def\B{#2}
  \def\PointB{coordinates {(\A,\B)}}
  \expandafter\addplot\PointB;
}

This will also work, just call it from within \begin{axis}...\end{axis}.

share|improve this answer
    
Is there a way to make this work without including \addplot coordinates in the point macro? I'd like to be able to just call \PointA wherever the syntax (<x>,<y>) is expected, without having to worry about whether I'm specifying a node/path or a plot coordinate. –  Jake Apr 16 '11 at 19:35
    
@Jake ...hard! What are you exactly trying to achieve, where are the co-ordinates originate from? –  Yiannis Lazarides Apr 16 '11 at 19:44
    
I have to admit that there's no real problem I'm trying to solve. It simply sparked from the question I linked to (tex.stackexchange.com/questions/15684/…). I just find it hard to accept that in two situations that call for the exact same syntax for specifying a coordinate, I shouldn't be able to replace the string of characters (x,y) with a macro. The linked question makes the point that dimensions can be saved in macros and then used in different contexts, so why can't it be done for coordinates...? –  Jake Apr 16 '11 at 19:55
    
@Jake I am sure if one traces back the parsing, it maybe possible with a number of expandafters, as you are looking at a very complicated parser that can do calcs etc. –  Yiannis Lazarides Apr 16 '11 at 19:59

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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