Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

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.

The generated diagrams.

\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,
    ]

    \addplot+[
        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,
    ]

    \addplot+[
        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}

Thank you for your help!

share|improve this question
    
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
add comment

1 Answer

up vote 2 down vote accepted

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,
]
 \addplot table [
    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}

finding maximum value with pgfplotstable

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
    \pgfplotstableread{sample-data.dat}{\datatable}
    \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,
]
\addplot table [
    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}

Finding nearest x-value

share|improve this answer
    
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
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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