6

In another question concerning Access to logic coordinates on

Accessing the logic values of a TikZ coordinate

I used these functions, until I came to a scaled tikzpicture and then it was off. I now have added a factor for the scaling, but I am looking for a method to make it universal. That would mean the xcoord/ycoord would take the picture's scaling into account through a tikz/pgf variable.

\makeatletter
\newcommand\xcoord[2][center]{{%
  \pgfpointanchor{#2}{#1}%
  \pgfmathparse{\pgf@x/\pgf@xx}%
  \pgfmathprintnumber{\pgfmathresult}%
}}
\newcommand\ycoord[2][center]{{%
  \pgfpointanchor{#2}{#1}%
  \pgfmathparse{\pgf@y/\pgf@yy}%
  \pgfmathprintnumber{\pgfmathresult}%
 }}
 \makeatother

Any suggestion to that effect?

An MWE is:

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

\makeatletter
\newcommand\xcoorda[2][center]{{%
  \pgfpointanchor{#2}{#1}%
  \pgfmathparse{\pgf@x/\pgf@xx}%
  \pgfmathprintnumber{\pgfmathresult}%
}}

\makeatletter
\newcommand\xcoord[2][center]{{%
 \pgfpointanchor{#2}{#1}%
 \pgfmathparse{\pgf@x/\pgf@xx/.17}%
 \pgfmathprintnumber{\pgfmathresult}%
}}

\newcommand\ycoorda[2][center]{{%
  \pgfpointanchor{#2}{#1}%
  \pgfmathparse{\pgf@y/\pgf@yy}%
  \pgfmathprintnumber{\pgfmathresult}%
}}
\makeatother

\usetikzlibrary{intersections}


\begin{document}

\begin{tikzpicture}[domain=-0.01:0.55,xscale=17,yscale=0.01] 
% the scaling is also in xcoord
\draw[-stealth,name path=xline] (0,0) -- (0.55,0);
\draw[stealth-stealth,name path=yline] (0,-220) -- (0,220);
\draw[color=blue,name path=func] (0,200) parabola bend (.25,-50) (.50,200);
\path[name intersections={of=func and xline,by={i1,i2}}];
\node[above=15pt] (i1label) at(i1) {\xcoord{i1}\%};
\draw[-stealth,green] (i1label.south) -- (i1);
\node[below=20pt,text width=2cm,align=center,draw,fill=red!25] (i1label_a) 
 at(i1) {\xcoorda{i1}\%\\ sans scaling \\ wrong!};
\draw[-stealth,red] (i1label_a.north) -- (i1);
\node[above=15pt] (i2label) at(i2) {\xcoord{i2}\%};
\draw[-stealth,green] (i2label.south) -- (i2);
\node[below=20pt,text width=2cm,draw,align=center,fill=red!25] (i2label_a) 
 at(i2) {\xcoorda{i2}\%\\ sans scaling \\ wrong!};
\draw[-stealth,red] (i2label_a.north) -- (i2);
\foreach \t in {10,20,...,50} {
\pgfmathparse{\t/100}\edef\v{\pgfmathresult}
  \draw[thin] (\v,10) -- (\v,-10) node[below] {\t\%};
}
\foreach \t in {-200,-100,...,200} {
 \draw[thin] (.010,\t) -- (-0.01,\t) node[left] {\small\t};
}
\end{tikzpicture}

\end{document}

I used a parabola in the MWE and marked the scaled and unscaled xcoord's in both cases.

Louis
  • 1,471
  • 1
    Could you add a minimal working example (MWE) that shows you it doesn't work with scaling? In my question I wanted the logical values of the coordinate system which are technically still the same after scaling, just aeh, scaled. So e.g. (2,1) is still (2,1) just placed somewhere else when you use scale. – Martin Scharrer Jul 20 '11 at 20:15

1 Answers1

6

The problem arises because \xcoorda is called inside a node, which resets the transformation matrix, so \pgf@xx is not scaled correctly. What you can do to avoid this is to save the transformation matrix into a macro at the start of the tikzpicture using \pgfgettransform{<macro>}, and set it inside the \xcoorda macro using \pgfsettransform{<macro>}. In order to use the resulting coordinate in a \pgfmathparse expression, I'd recommend turning the macro into a pgfmath function. I've included this approach in the code below.

get logical coordinates

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{intersections}

\makeatletter
\newcommand\xcoorda[2][center]{{%
%
% Set the transformation matrix that was saved at the beginning of the tikzpicture
%
  \pgfsettransform{\transform}%
  \pgfpointanchor{#2}{#1}%
  \pgfmathparse{\pgf@x/\pgf@xx}%
  \pgfmathresult%
}}

\pgfmathdeclarefunction{xcoord}{1}{
  \pgfsettransform{\transform}%
  \pgfpointanchor{#1}{center}%
  \pgfmathparse{\pgf@x/\pgf@xx}%
}

\makeatother

\begin{document}

\begin{tikzpicture}[domain=-0.01:0.55,xscale=17,yscale=0.01] 

% Save the transformation matrix
\pgfgettransform{\transform}

\draw[-stealth,name path=xline] (0,0) -- (0.55,0);
\draw[stealth-stealth,name path=yline] (0,-220) -- (0,220);
\draw[color=blue,name path=func] (0,200) parabola bend (.25,-50) (.50,200);
\path[name intersections={of=func and xline,by={i1,i2}}];
\node[below=20pt,text width=2cm,align=center,draw,fill=green!25] (i1label_a) 
 at(i1) {\xcoorda{i1}\\correct};
\draw[-stealth,red] (i1label_a.north) -- (i1);
\node[below=20pt,text width=2cm,draw,align=center,fill=green!25] (i2label_a) 
 at(i2) {\pgfmathparse{xcoord("i2")*100}\pgfmathprintnumber{\pgfmathresult}\,\%\\ correct};
\draw[-stealth,red] (i2label_a.north) -- (i2);
\foreach \t in {10,20,...,50} {
\pgfmathsetmacro\v{\t/100}
  \draw[thin] (\v,10) -- (\v,-10) node[below] {\t\%};
}
\foreach \t in {-200,-100,...,200} {
 \draw[thin] (.010,\t) -- (-0.01,\t) node[left] {\small\t};
}
\end{tikzpicture}

\end{document}

If you're using PGFplots, you can avoid having to manually save and restore the coordinate transformation, since in this case you can use \pgfplotsunitxlength, which holds the length of the x unit vector multiplied by 1000, and \pgfplotspointaxisorigin, which holds the point (0,0) of the current axis:

pgfplots logical coordinates

\documentclass{article}
\usepackage{pgfplots}
\usetikzlibrary{intersections}

\newcommand\xcoord[2][center]{{%
    \pgfpointanchor{#2}{#1}%
    \pgfgetlastxy{\ix}{\iy}%
    \pgfplotspointaxisorigin%
    \pgfgetlastxy{\ox}{\oy}
    \pgfmathparse{(\ix-\ox)/\pgfplotsunitxlength/1000}
    \pgfmathprintnumber{\pgfmathresult}}
}

\begin{document}

\vspace{1cm}
\begin{tikzpicture}
\begin{axis}[
    domain=0:0.5,
    samples=100,
    no markers,
    axis lines=middle,
    enlarge x limits=upper,
    enlarge y limits=true,
    xticklabel=\pgfmathparse{\tick*100}\pgfmathprintnumber{\pgfmathresult}\,\%,
    x axis line style={{name path global=xaxis}}
    ]
\addplot +[name path global=plot] {4000*(x-0.25)^2-50};

\pgfplotsextra{
\fill [name intersections={of=xaxis and plot, name=i, total=\t}] 
    [red, every node/.style={black}] 
    (i-1) circle (2pt) node [pin={\xcoord{i-1}}] {}
    (i-2) circle (2pt) node [pin={\xcoord{i-2}}] {};
}
\end{axis}
\end{tikzpicture}
\end{document}
Jake
  • 232,450
  • Thank you this is exactly what I needed. I did not use pgfplots as in my document where this is used I also draw cash flow diagrams and the ycomb does not do what I want -- arrow lines pointing away from the time or x-axis. – Louis Jul 21 '11 at 07:08
  • 1
    That sounds like an interesting application! Have you taken a look at http://tex.stackexchange.com/questions/20296/how-can-i-draw-dirac-deltas-with-arrow-heads-with-pgfplots/20350#20350? If not, you might want to consider posting a question about it, PGFplots is flexible and powerful enough to accommodate something like that, and I'm sure it would be useful for others. – Jake Jul 21 '11 at 09:51
  • At this stage I am a bit short of time, else I would have tried to write something for PGFplots to draw cash flow diagrams and add some of the possible calculations associated, like PV,FV & Uniform series. – Louis Jul 21 '11 at 10:24
  • I wanted also convert the coordinates to percentages, so I tried something like: \pgfmathparse{100*\xcoorda{i1}}\edef\v{\pgfmathresult}; but it does not work. – Louis Jul 21 '11 at 10:27
  • 1
    I've changed the answer to give an approach that properly returns the value as a number (not as a formatted string, as \pgfmathprintnumber does). – Jake Jul 21 '11 at 11:45
  • I looked at that link. At that stage my tikz knowledge was non-existent and I could not get it to work the way I wanted to. I will revisit the concept and see if I can build on it. The biggest problem with many of these superb packages is the steep uphill to get it to work the way one wants. The tikz doc is only 700+ pages and when I changed from pstricks (does not work well with many pictures) I wanted to get to the end as fast as possible. I eventually created a file with only the pictures and then pasted them one by one over. – Louis Jul 21 '11 at 11:49
  • That now works perfectly and I learnt a few more things. TNX! – Louis Jul 21 '11 at 12:00
  • So I played with it. I used the PGFplots example. I changed to plot to: \addplot +[name path global=plot] {(x-.25)(x-2.07)(x-4.09)(x-5.72)(x-8.04)}; changed the domain to 0:8.2 and commented the xticklabels out. The result was fractions in stead of the values are now shown (/10). I was also wondering how one would use a foreach in this case? – Louis Jul 21 '11 at 14:21
  • @Louis: I can't reproduce the behaviour of fractions being shown. It might be a good idea to post this as a new question. The same goes for the second part of your comment regarding the usage of foreach (I don't think I understand your question here). – Jake Jul 22 '11 at 05:22
  • I will just do that. – Louis Jul 23 '11 at 20:44