13

In answering PGFPlots: How to draw a label at a zero of a function?, I got stuck on converting a length in pt to the actual coordinate value in the axis cs system.

Here I only need the x value, but my question is how does one obtain the actual x/y values of a coordinate once you have their physical location.

Sub-Question:

  • Why does the circle not get drawn for the intersection on the left once I use \pgfextra?

enter image description here

Notes:

Code:

\documentclass[border=2pt]{standalone}
\usepackage{pgfplots}
\usetikzlibrary{intersections}

% https://tex.stackexchange.com/questions/33703/extract-x-y-coordinate-of-an-arbitrary-point-in-tikz \newdimen\XCoord \newdimen\YCoord \newcommand*{\ExtractCoordinate}[1]{\path (#1); \pgfgetlastxy{\XCoord}{\YCoord};}%

\begin{document}

\begin{tikzpicture} \begin{axis}[ axis x line=middle, axis y line=middle, domain=-4:7, xmax=7, ] \addplot[no marks,blue,thick, name path global=My Graph] {xx-4x-7}; \addplot[no marks,draw=none, name path global=x Axis ] {0}; \fill[red,name intersections={of=My Graph and x Axis,total=\t}] \foreach \s in {1,...,\t}{ \pgfextra{\ExtractCoordinate{intersection-\s}} (intersection-\s) circle (2pt) node [above] {$\XCoord$} }; \end{axis} \end{tikzpicture} \end{document}

Peter Grill
  • 223,288
  • Should I copy my answer here? – John Kormylo Apr 07 '14 at 16:40
  • BTW, you've got a \path inside a \fill (not good). You would be better off using \whereami (see http://tex.stackexchange.com/questions/168452/how-can-i-draw-a-3d-three-sided-5-7-9-triangle-with-tikz-or-pstricks/168482#168482). – John Kormylo Apr 08 '14 at 03:35

2 Answers2

8

Originally posted on PGFPlots: How to draw a label at a zero of a function? There may be a better way than this, but I haven't found one yet.

tick marks

\documentclass[border=2pt]{standalone}
\usepackage{pgfplots}
\usetikzlibrary{intersections}

\newlength{\len}
\newlength{\plotwidth}
\newcommand{\getvalue}[1]{\pgfkeysvalueof{/pgfplots/#1}}

%output will be given by \pgfmathresult
\newcommand{\xcoord}[1]% #1 = node name
{\pgfplotsextra{%
  \pgfextractx{\len}{\pgfpointdiff{\pgfplotspointaxisxy{0}{0}}{\pgfpointanchor{#1}{center}}}%
  \pgfextractx{\plotwidth}{\pgfpointdiff{\pgfplotspointaxisxy{\getvalue{xmin}}{0}}%
    {\pgfplotspointaxisxy{\getvalue{xmax}}{0}}}%
  \pgfmathparse{\len*(\getvalue{xmax}-\getvalue{xmin})/\plotwidth}%
}}

\begin{document}

\begin{tikzpicture}
    \begin{axis}[
            axis x line=middle,
            axis y line=middle,
            domain=-4:7
        ]
        \addplot[no marks,blue,thick, name path global=My Graph] {x*x-4*x-7};
        \addplot[no marks,draw=none, name path global=x Axis] {0};
        \path[name intersections={of=My Graph and x Axis,total=\t}];

        \draw[very thin,color=gray] (intersection-1) -- +(0,-5mm) coordinate(tick1);
        \xcoord{tick1}%
        \node[below] at (tick1) {$\pgfmathresult$};

        \draw[very thin,color=gray] (intersection-2) -- +(0,-5mm) coordinate(tick2);
        \xcoord{tick2}%
        \node[below] at (tick2) {$\pgfmathresult$};
     \end{axis}

\end{tikzpicture}
\end{document}

It should be noted than you get the wrong answer if \xcoord is inside a node (text field) or a path, and obviously if any other \pgfmath calculation occurs between it an \pgfmathresult. Also, \pgfplotsconvertunittocoordinate and \pgfplotsunitxlength were tried unsucessfully.

John Kormylo
  • 79,712
  • 3
  • 50
  • 120
  • This looks good, except for assuming that there are two intersections -- but that wasn't the thrust of this question (so is acceptable). Also, all numbers should be in math mode, otherwise the negative sign is nor properly formatted (so use $\pgfmathresult$ instead of \pgfmathresult in the \node. – Peter Grill Apr 08 '14 at 03:43
  • @Peter Grill - I tried \foreach without success. I haven't tried \loop \repeat yet. The other suggestion has been implemented. – John Kormylo Apr 08 '14 at 05:52
5

Expanding on John's very nice answer, I've copied some definitions from Plot functions and their point of intersection. It is in turn based on Jake's previous code linked in that question.

Here, one of the main issues is the sample number and number of intersection computations. If you consider the following example, I've commented out the node that displays the number of intersections found which might be helpful to see the problem.

\documentclass[border=2pt]{standalone}
\usepackage{pgfplots}
\pgfplotsset{compat=1.10}
\usetikzlibrary{intersections}
\makeatletter
\def\markxof#1{%
\pgf@process{\pgfpointanchor{#1}{center}}%
\pgfmathparse{\pgf@x/\pgfplotsunitxlength 
             +\pgfplots@data@scale@trafo@SHIFT@x)/
             10^\pgfplots@data@scale@trafo@EXPONENT@x
             }%
}
\makeatother
\begin{document}

\begin{tikzpicture}
    \begin{axis}[
        axis x line=middle,
        axis y line=middle,
        domain=-4:4,
        after end axis/.code={
          \foreach \x in {1,...,\mytot}{
             \draw[very thin,color=gray] (intersection-\x) -- +(0,-5mm) coordinate(tick\x);
             \node[below] at (tick\x) 
               {\markxof{tick\x}$\pgfmathprintnumber[fixed,precision=2]\pgfmathresult$};
          }
       }
    ]
    \addplot[no marks,blue,thick, name path global=My Graph,smooth] {x^3-8*x+3};
    \addplot[no marks,draw=none, name path global=x Axis] {0};
    \path[name intersections={of=My Graph and x Axis,total=\mytot},
          /utils/exec={\xdef\mytot{\mytot}}]
        %node[right] at (axis cs:1,15) {\mytot\ intersections}
        ;
    \end{axis}
\end{tikzpicture}

\end{document}

The reason is that if the sample number is high enough the paths that form the general path get too small and trigger false positives for intersection. One option might be drawing once the curve invisibly (draw=none) to get the intersections with smooth version and overlay the original path on top as visible. Add remove the smooth option below.

Finally, the total count of intersections doesn't survive the path (let alone the axis) since it is probably designed to be used immediately in the same path.

enter image description here

percusse
  • 157,807