11

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] {x*x-4*x-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}
7

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.

  • 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 8 '14 at 3:43
  • @Peter Grill - I tried \foreach without success. I haven't tried \loop \repeat yet. The other suggestion has been implemented. – John Kormylo Apr 8 '14 at 5: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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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