# Drawing Vertical Arrows in Coordinate System Using Pgfplot

I have a series of data plots, an example of which is depicted below, and I would like to draw a vertical line through a particular x-coordinate on each plot, so that the head of the arrow is is inline with the point having the maximum y-coordinate. After looking through the manual, I found nothing that would help me accomplish this directly (axis cs:<x>,<y> only lets me do this for each plot individually, and I will be generating thousands using one template).

Extracting the y-coordinate of the top of the plot (using \pgfextract with s.north) eluded my efforts, but even this would not solve the problem since I would still need to subtract from it the default y-limit enlargement value.

\documentclass{article}
\usepackage{filecontents}
\usepackage[top=2cm,bottom=2cm,left=2cm,right=2cm]{geometry}
\usepackage{pgfplots}
\usepackage{tikz}

\begin{filecontents}{sample-data.dat}
{Data Values}   Count
0   6
0.109827    86
0.219654    300
0.329481    662
0.439308    1085
0.549135    1366
0.658962    1470
0.768789    1333
0.878616    1200
0.988443    904
1.09827 620
1.2081  417
1.31792 247
1.42775 164
1.53758 72
1.64741 30
1.75723 21
1.86706 8
1.97689 6
2.08671 2
2.19654 1
2.41619 0
\end{filecontents}

\providecommand{\lineplotxy}[2]{
\begin{tikzpicture}
\begin{axis}[
xlabel=Data Values,
ylabel=Count,
title=#1,
]

sharp plot
]
table [
x=Data Values,
y=Count
] {#2};

\end{axis}
\end{tikzpicture}
}

\providecommand{\lineplotxymarked}[2]{
\begin{tikzpicture}
\begin{axis}[
xlabel=Data Values,
ylabel=Count,
title=#1,
]

sharp plot
]
table [
x=Data Values,
y=Count
] {#2};

\draw[red,->,shorten >=2pt,>=stealth] (axis cs:2,0) -- (axis cs:2,1500);

\end{axis}
\end{tikzpicture}
}

\begin{document}

\centering
\begin{figure}[!h]
\resizebox{\textwidth}{!}{
\lineplotxy{Initial Diagram}{sample-data.dat}
\lineplotxymarked{Desired Output}{sample-data.dat}
}
\end{figure}

\end{document}


-
Is the x-coordinate of the lower end of the arrow always a data point, or do you want use arbitrary values and interpolate linearly between the two closest data points? – Jake Jun 29 '11 at 0:26
The x-coordinate of the lower end of the arrow is a predetermined data point -- the restriction on the height of the arrow was mainly an aesthetic one. – void-pointer Jun 29 '11 at 0:31

You can use the pgfplotstable package, which is part of PGFplots, to find the largest value in the data by sorting the table and extracting the first element of the sorted table

\documentclass{article}
\usepackage{filecontents}
\usepackage{pgfplots}
\usepackage{pgfplotstable}

\begin{filecontents}{sample-data.dat}
{Data Values}   Count
0   6
0.109827    86
0.219654    300
0.329481    662
0.439308    1085
0.549135    1366
0.658962    1470
0.768789    1333
0.878616    1200
0.988443    904
1.09827 620
1.2081  417
1.31792 247
1.42775 164
1.53758 72
1.64741 30
1.75723 21
1.86706 8
1.97689 6
2.08671 2
2.19654 1
2.41619 0
\end{filecontents}

\pgfplotstablesort[sort key={[index] 1},sort cmp={float >}]{\sorted}{sample-data.dat}
\pgfplotstablegetelem{0}{[index] 1}\of{\sorted}
\let\maxvalue=\pgfplotsretval

\begin{document}
\begin{tikzpicture}
\begin{axis}[
xlabel=Data Values,
ylabel=Count,
]
x=Data Values,
y=Count
] {sample-data.dat};

\draw[red,->,>=stealth] (axis cs:2,0) -- (axis cs:2,\maxvalue)
node [anchor=west,black] at (axis cs:2,\maxvalue) {\maxvalue};

\end{axis}
\end{tikzpicture}
\end{document}


And just to show what else is possible with pgfplotstable, here's a macro that takes an x-value as the argument, finds the data point in the table with the nearest x-value, and assembles the two points for the arrow:

\documentclass{article}
\usepackage{filecontents}
\usepackage{pgfplots}
\usepackage{pgfplotstable}

\begin{filecontents}{sample-data.dat}
{Data Values}   Count
0   6
0.109827    86
0.219654    300
0.329481    662
0.439308    1085
0.549135    1366
0.658962    1470
0.768789    1333
0.878616    1200
0.988443    904
1.09827 620
1.2081  417
1.31792 247
1.42775 164
1.53758 72
1.64741 30
1.75723 21
1.86706 8
1.97689 6
2.08671 2
2.19654 1
2.41619 0
\end{filecontents}

\newcommand{\assemblearrowpoints}[1]{
% Read table, save column names
\pgfplotstablegetcolumnnamebyindex{0}\of{\datatable}\to{\xname}
\pgfplotstablegetcolumnnamebyindex{1}\of{\datatable}\to{\yname}

% Find maximum value in table by sorting and then extracting first element of sorted table
\pgfplotstablesort[sort key={\yname},sort cmp={float >}]{\sorted}{sample-data.dat}
\pgfplotstablegetelem{0}{\yname}\of{\sorted}
\let\maxy=\pgfplotsretval

% Create new "target" column with squared difference between x values and target x
\pgfplotstablecreatecol[
create col/expr={(\thisrow{\xname}-#1)^2}]{target}{\datatable}
% Sort from lowest to highest squared difference
\pgfplotstablesort[sort key={target},sort cmp={float <}]{\targettable}{\datatable}
\pgfplotstablegetelem{0}{\xname}\of{\targettable}
\let\lowerx=\pgfplotsretval
\pgfplotstablegetelem{0}{\yname}\of{\targettable}
\let\lowery=\pgfplotsretval

% Assemble points for arrow
\def\lowerpoint{axis cs:\lowerx,\lowery}
\def\highpoint{axis cs:\lowerx,\maxy}
}

\begin{document}
\assemblearrowpoints{2}

\begin{tikzpicture}
\begin{axis}[
xlabel=Data Values,
ylabel=Count,
]
x=Data Values,
y=Count
] {sample-data.dat};

\draw[red,->,>=stealth] (\lowerpoint)
node [black,anchor=south west] {\lowery}
-- (\highpoint)
node [pos=0.5,black,anchor=west] {\pgfmathparse{int(\maxy-\lowery)}\pgfmathresult}
node [black,anchor=west] {\maxy};
\end{axis}
\end{tikzpicture}
\end{document}


-
Again, exactly what I was looking for -- I used pgfplotstable before for relatively mundane applications but I never knew that it could sort through data. Thanks a bunch! – void-pointer Jun 29 '11 at 1:35