# Extract x, y coordinate of an arbitrary point in TikZ

I need a macro to extract the x and y coordinates from an arbitrary point, like (3,4), or like (A), or like ([xshift=-2pt] A.north west), where A is the name of a node.

I've seen the solution

 \newdimen\mydim
\newcommand\getx[1]{
\pgfextractx\mydim{\pgfpointanchor{#1}{center}}
}


elsewhere on StackExchange, but this obviously won't work for all the cases described above. I need to be able to call \getx{(3,4)} and \getx{(A)} and \getx{([xshift=-2pt] A.north west)}, and for them all to work equally well, in this case putting the x-coordinate of the argument into the variable \mydim.

I'm kind of stunned how hard this seems to be! Surely I've missed something...

-
You could use \coordinate (tmp) at #1 and then extract the coordinates from (tmp). – Caramdir Nov 4 '11 at 23:14
Great! Why not post it as a solution, unless you're not bothered about the rep :). – Jamie Vicary Nov 4 '11 at 23:17
I'm not bothered about the rep and I currently don't want to write and test a full solution :). Maybe a bit later (unless someone else already provides a full solution by then). – Caramdir Nov 4 '11 at 23:20
For a lot of these cases the let operation looks like a good fit. You can just go let \p1 (3,4) in (\x1,0) -- (\x1,\y1) then \x1 and \y1 will hold the 3 and 4 respectively. You can even do multiple points at once. All of this is within a \path the TikZ manual discusses it on page 150. – Roelof Spijker Nov 5 '11 at 0:35
Roelof's answer is a good one for my case. FYI, the "let" command is discussed in section 14.15 of the TikZ manual for version 3.0.0, starting on page 161. – Derek Sep 9 '14 at 0:40

You can use \pgfgetlastxy{\XCoord}{\YCoord} to extract the x,y coordinate of the most recently used point into the dimension registers \XCoord and {\YCoord}. To make the point the most recently used, I use \path macro just before extraction. Here is an example where I define points, extract the x and y coordinates, and then label them via the extracted coordinates:

\documentclass[border=2pt]{standalone}

\usepackage{tikz}
\usetikzlibrary{calc}

\newdimen\XCoord
\newdimen\YCoord

\newcommand*{\ExtractCoordinate}[1]{\path (#1); \pgfgetlastxy{\XCoord}{\YCoord};}%
\newcommand*{\LabelCurrentCoordinate}[2]{\fill [#1] ($(\XCoord,\YCoord)$) circle (2pt) node [right] {#2}}%

\begin{document}
\begin{tikzpicture}
\coordinate (A) at (3,2);
\coordinate (B) at ([xshift=-15pt] A.north west);

\ExtractCoordinate{$(A)$};
\LabelCurrentCoordinate{red}{A};

\ExtractCoordinate{$(B)$};
\LabelCurrentCoordinate{blue}{B};

\ExtractCoordinate{$(1,1)$};
\LabelCurrentCoordinate{green}{C};
\end{tikzpicture}
\end{document}

-
If I use different new dimensions for different points, both still end up the same size. Is it possible to save the value somehow? – cfr Oct 23 '15 at 16:10
@cfr: Not sure I understand. Can you post a new question with a MWE that reproduces the problem? – Peter Grill Oct 24 '15 at 6:53

The answers from Peter, Jamie, and wh1t3 (the last one in the comments) are all fine. I'm adding this as a "low level" version since this is often something that one wants to do as a part of a bigger thing, and then it can be useful to know how to do it at this lower level.

The TikZ command that scans a coordinate and figures out where it actually corresponds to is called \tikz@scan@one@point. It sort-of takes two arguments. The first is a macro, the second is the point to be scanned. The "sort-of" is because the second argument isn't an argument, it's just the bare coordinate. The coordinate is parsed until TikZ feels that it understands it enough to produce an honest x-y coordinate on the page, whereupon is called the macro with that x-y coordinate as its argument (specifically, it calls \themacro{\pgfpoint{x-coord}{y-coord}}. By specifying the macro to be \@firstofone (or \pgfutil@firstofone if we want to be good PGFers) we can set \pgf@x and \pgf@y to be those coordinates. If we want to save them, we could either pass a fancy saving macro or simply save the values of \pgf@x and \pgf@y afterwards.

Here's a simple example where we define a macro that takes three arguments, being the coordinate and two macros in which to save the x and y coordinates.

\documentclass{article}
%\url{http://tex.stackexchange.com/q/33703/86}
\usepackage{tikz}
\makeatletter
\newcommand{\gettikzxy}[3]{%
\tikz@scan@one@point\pgfutil@firstofone#1\relax
\edef#2{\the\pgf@x}%
\edef#3{\the\pgf@y}%
}
\makeatother
\begin{document}
\begin{tikzpicture}
\draw (0,0) .. controls +(1,0) and +(-1,0) .. node[auto] (A) {A} (3,3);
\gettikzxy{(A)}{\ax}{\ay}
\begin{scope}[rotate=45,xshift=3cm]
\draw (0,0) -- node[auto] (B) {B} (3,2);
\end{scope}
\gettikzxy{(B)}{\bx}{\by}
\gettikzxy{([xshift=-2cm] A.north west)}{\cx}{\cy}
\end{tikzpicture}
\end{document}


(The last one is taken from your question but I changed the shift to 2cm so that it would be more obvious.)

The result is:

-
I was very keen on using this, but unfortunately it doesn't seem to work with pgfplots: I add this: \begin{axis} ; \addplot[name path global=cfunc,blue,domain=0:3.1] {sin(deg(x))} ; \node[auto, name path global=D] (D) at (2,2) {D} ; \gettikzxy{(D)}{\ax}{\ay} ; \end{axis} right before the \end{tikzpicture} in this snippet, and the failure is: "Package pgf Error: No shape named D is known." (neither are the other nodes from an axis environment known). Any possibility for that kind of use? – sdaau Feb 16 '14 at 23:35
@sdaau My guess is that the axis environment saves up its drawing commands until the end, so the D node is not positioned until the axis environment is finished. Within the axis environment then \gettikzxy is executed straight away and so before D is positioned. If you shift the \gettikzxy after the \end{axis} then it seems to work. Can you use it like that? – Loop Space Feb 17 '14 at 10:18
Thanks for the answer @LoopSpace - it makes sense; I'd guess it will work that way (unfortunately, I lost the original example leading to the comment). Cheers! – sdaau Jun 26 '14 at 5:27

This feels very wrong, but I'll do it anyway...

\newdimen{\tempx}
\newdimen{\tempy}
\newcommand\getxy[1]{
\coordinate (tmp) at #1;
\pgfextractx\tempx{\pgfpointanchor{tmp}{center}}
\pgfextracty\tempy{\pgfpointanchor{tmp}{center}}
}

-
Suggestion: Compile this code snippet in a working MWE and it will be more valuable. That way interested users can see exactly how to utilize your "wrong doings". :) – Werner Nov 5 '11 at 1:25

For the sake of convenience, I've written these small \def and macro that should help to pretty print point coordinates.

\documentclass{minimal}
\pdfminorversion 7
\pdfobjcompresslevel 3
\usepackage{pgf}
\usepackage{tikz}
\usetikzlibrary{hobby,calc,intersections}
\begin{document}
\begin{tikzpicture}[scale=0.7]
\pgfkeys{/pgf/number format/.cd,fixed,precision=1,dec sep={,}}
\def\pttocm#1{\pgfmathparse{#1 / 19.93333
}\pgfmathprintnumber{\pgfmathresult}}

\newcommand{\printcoords}[1]{
\newdimen\posx
\pgfextractx{\posx}{\pgfpointanchor{#1}{center}}
\newdimen\posy
\pgfextracty{\posy}{\pgfpointanchor{#1}{center}}
(\pttocm\posx ; \pttocm\posy )
}

\draw [thick,->] (-4.3,0) -- (4.3,0) node[below] {$x$} ;
\draw [thick,->] (0,-2.3) -- (0,7.2) node[left] {$y$};
\draw [dotted] (-4.3,-2.3) grid (4.3,7.2) ;
\draw [name path=h,thick] plot [smooth] coordinates {(-4,-2)(-3,2)(-2,6)(0,2)
(2,-2)(3,4)} ;
\draw (0,0) node [below left] {0} ;
\draw (1,0) node [below] {1} ;
\draw (0,1) node [left] {1} ;
\foreach \i in {-4,-3,-2,-1,1,2,3,4}
{ \draw[very thick] (\i,0) -- (\i,-0.15) ; }
\foreach \i in {-2,-1,1,2,3,4,5}
{ \draw[very thick] (0,\i) -- (-0.15,\i) ; }
\foreach \i/\j in { -4/-2, 3/4 }
{ \draw (\i,\j) node[fill,circle, inner sep=1pt] {} ; }
\draw (-3,-1) node[xshift=-2mm,yshift=1mm] {${C}_h$} ;

\draw [name path=g,thick,red] plot[domain=-4.3:4.3]
(\x,{ -(\x-2)*2/3 }) ;
\draw [dashed,very thick,red] (2,0) -- (2,-2) -- (0,-2) ;
\draw [name path=eq,red] (-4.3,2) -- (4.3,2) ;
\path [name intersections ={of = h and eq }] ;
\coordinate (A) at (intersection-1) ;
\draw[red,thick] (A) node[draw,circle] {} ;
\draw[red] (A) node[below left] {\printcoords{A}} ;
\coordinate (B) at (intersection-2) ;
\draw[red,thick] (B) node[draw,circle] {} ;
\draw[red] (B) node[above right] {\printcoords{B}} ;
\coordinate (C) at (intersection-3) ;
\draw[red,thick] (C) node[draw,circle] {} ;
\draw[red] (C) node[above right] {\printcoords{C}} ;
\path [name intersections ={of = h and g }] ;
\coordinate (D) at (intersection-1) ;
\draw[red,thick] (D) node[draw,circle] {} ;
\draw[red] (D) node[above right] {\printcoords{D}} ;
\coordinate (E) at (intersection-2) ;
\draw[red,thick] (E) node[draw,circle] {} ;
\draw[red] (E) node [above right] {\printcoords{E}} ;
\coordinate (F) at (intersection-3) ;
\draw[red,thick] (F) node[draw,circle] {} ;
\draw[red] (F) node[above right] {\printcoords{F}} ;
\end{tikzpicture}
\end{document}


It even handles multiple intersection points, thanks to the intersection library.

-
Welcome to TeX.SX! While this might answer the question, it is always better to post a full example such that users can test immediately – Christian Hupfer Dec 7 '14 at 11:30

I had a matrix of points, named say e1, ..., e6 on the y-coordinate and S1, ..., S5 along the x-coordinate. My goal was to draw a small square at the coordinates (ei -| Sj) only for some given points (like an adjacency matrix).

I was trying to use the previous solutions for extracting x and y component of a point from a list, like

\foreach \pt in {(1 ,2), (1, 3), (2, 2), (2, 4)} {
\parsept{\x}{\y}{\pt}
\fill (S\x |- e\y) +(-1, -1) rectangle +(1, 1);
}


Note that in this case the previous solutions will not work, because they extract the raw coordinate computed by TikZ, so the TeX engine would look for some point named S28.221344pt (failing).

So I ended up writing a naive macro for parsing ( x , y ) expressions. The solution may be useful for other readers that require the coordinates to be parsed literally:

\makeatletter
\def\parsept#1#2#3{%
\def\nospace##1{\zap@space##1 \@empty}%
\def\rawparsept(##1,##2){%
\edef#1{\nospace{##1}}%
\edef#2{\nospace{##2}}%
}%
\expandafter\rawparsept#3%
}
\makeatother


The macro strips away all spaces in the argument (so \parsept{\x}{\y}{( a b, c)} will yield \x=ab and \y=c), but I couldn't make \ignorespaces and \unskip working in this context. Credits for removing spaces go to David Carlisle's answer.

-