[Tex/LaTex] pgfplots: Placing node on a specific x-position

pgfplots

I'm trying to put some arrows on the left and right side of the maximum of a curve. The arrows should point along the curve. My problem is that if I use the [pos=X] notation I don't know where I am in relation to the maximum. And if I use absolute coordinates the node is not sloped.

\documentclass{article}
\usepackage{pgfplots}
\usetikzlibrary{shapes.geometric}
\pgfplotsset{compat=1.7}

\begin{document}
\begin{tikzpicture}
\tikzset{myarrow/.style=
         {sloped,isosceles triangle,anchor=apex,fill=black,inner sep=2pt}}
\begin{axis}
\addplot [smooth] {-x^2}
 node[pos=0.4,myarrow,rotate=180]{} %ok
 node[pos=0.6,myarrow]{}; %ok

\addplot[smooth,green] {-x^2+2*x-4}
 node[pos=0.4,myarrow,rotate=180]{}
 node[pos=0.6,myarrow]{} %wrong side
 node[myarrow,fill=red] at (axis cs:4,-12){}; %wrong rotation!
\end{axis}

\end{tikzpicture} 
\end{document}

enter image description here

Edit: Some remark about Jake's answer

Jake's code (naturally) works but

  • for my case it is a bit too complicated. Jake gets the correct rotation for the arrow by drawing a short path from x-1pt to x (cool idea). He gets the coordinates for this small path with intersections. But as my plot is based on a function I can simply calculate the values (e.g. with \pgfmathparse) and then draw the small path after the plot:

    \path  (axis cs:3.99,-11.94012) -- (axis cs:4,-12) node[pos=1,myarrow]{};
    

    The same can also be achieved by redrawing the plot but with a restricted domain:

    \addplot[draw=none,domain=3.99:4] {\MyFunction{x}}
     node[pos=1,myarrow,fill=yellow]{};
    
  • I also looked if there is a way to decide where I am relative to the maximum (so that I can change the rotation) and in theory it is possible: If I use the code found here pgfplots: mark max/min value of a function \pgfplots@metamax is known after the plot and can be used in calculations.

Best Answer

Here's one approach based on my answer to Label plots in pgfplots without entering coordinates manually. It finds the intersections between the plot and two vertical lines to position and rotate the node. Using this, you can place an arbitrary node at x=4 by adding the option add node at x={4}{[<node options>]{<node text>}} or add node at x={4}{<node text>} to the \addplot options. I've also added an equivalent style add node at y, which places nodes at a specified vertical coordinate on the plot.

Here's an example for using these styles:

\addplot [
    add node at x={-3}{[myarrow, blue]{}},
    add node at x={3}{[orange, fill=white, opacity=0.75,text opacity=1, sloped]{Sloped}}
    ] {-x^2};

\addplot[
    green,
    add node at y={-30}{[myarrow, green]{}},
    add node at y={-5}{Some text}
] {-x^2+2*x-4};

\documentclass{standalone}
\usepackage{pgfplots}
\usetikzlibrary{shapes.geometric, intersections}
\pgfplotsset{compat=1.7}

\begin{document}
\begin{tikzpicture}

\tikzset{
    myarrow/.style={
        sloped,
        isosceles triangle,
        anchor=apex,
        fill=black,
        inner sep=2pt
    }
}

\makeatletter
\def\parsenode[#1]#2\pgf@nil{%
    \tikzset{label node/.style={#1}}
    \def\nodetext{#2}
}

\tikzset{
    add node at x/.style 2 args={
        name path global=plot line,
        /pgfplots/execute at end plot visualization/.append={
                \begingroup
                \@ifnextchar[{\parsenode}{\parsenode[]}#2\pgf@nil
            \path [name path global = position line #1-1]
                ({axis cs:#1,0}|-{rel axis cs:0,0}) --
                ({axis cs:#1,0}|-{rel axis cs:0,1});
            \path [xshift=1pt, name path global = position line #1-2]
                ({axis cs:#1,0}|-{rel axis cs:0,0}) --
                ({axis cs:#1,0}|-{rel axis cs:0,1});
            \path [
                name intersections={
                    of={plot line and position line #1-1},
                    name=left intersection
                },
                name intersections={
                    of={plot line and position line #1-2},
                    name=right intersection
                },
                label node/.append style={pos=1}
            ] (left intersection-1) -- (right intersection-1)
            node [label node]{\nodetext};
            \endgroup
        }
    },
    add node at y/.style 2 args={
        name path global=plot line,
        /pgfplots/execute at end plot visualization/.append={
                \begingroup
                \@ifnextchar[{\parsenode}{\parsenode[]}#2\pgf@nil
            \path [name path global = position line #1-1]
                ({axis cs:0,#1}-|{rel axis cs:0,0}) --
                ({axis cs:0,#1}-|{rel axis cs:1,1});
            \path [yshift=1pt, name path global = position line #1-2]
                ({axis cs:0,#1}-|{rel axis cs:0,0}) --
                ({axis cs:0,#1}-|{rel axis cs:1,1});
            \path [
                name intersections={
                    of={plot line and position line #1-1},
                    name=left intersection
                },
                name intersections={
                    of={plot line and position line #1-2},
                    name=right intersection
                },
                label node/.append style={pos=1}
            ] (left intersection-1) -- (right intersection-1)
            node [label node] {\nodetext};
            \endgroup
        }
    }
}
\makeatother
\begin{axis}[smooth]
\addplot [
    add node at x={-3}{[myarrow, blue]{}},
    add node at x={3}{[orange, fill=white, opacity=0.75,text opacity=1, sloped]{Sloped}}
    ] {-x^2};

\addplot[
    green,
    add node at y={-30}{[myarrow, green]{}},
    add node at y={-5}{Some text}
] {-x^2+2*x-4};
\end{axis}

\end{tikzpicture} 
\end{document}