13
\documentclass{standalone}

\usepackage{pgfplots}
\usepackage{pgfplotstable}
\pgfplotsset{compat=1.10}

\pgfplotstableread{
0.01    1.00
0.02    2.00
0.03    3.00
0.04    4.00
0.05    5.00
}\datatable

\begin{document}
\begin{tikzpicture}
\begin{axis}[ymin=0, ymax=6]
\addplot table  {\datatable}
node[pos=0.0, pin=above:"Unidentified peak"]{} % pos only allows for fractional value
node[pos=0.2, pin=above:"Bragg peak"]{} % pos only allows for fractional value
node[pos=1.0, pin=above:"my custom label"]{} % pos only allows for fractional value
;

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

UPDATE: A slightly shorter version of the second solution in the answer by @Matthew Leingang:

\documentclass{standalone}

\usepackage{pgfplots}
\usepackage{pgfplotstable} % For \pgfplotstableread
\pgfplotsset{compat=1.10}

\pgfplotstableread{
0.01    1.00
0.011   2.00
0.012   3.00
0.013    4.00
0.05    5.00
}\datatable
% \pgfplotstableread{results.dat}\datatable

\pgfplotstablegetrowsof{\datatable}
\pgfmathsetmacro{\N}{\pgfplotsretval}  

\begin{document}
\begin{tikzpicture}
\begin{axis}[ymin=0, ymax=6]
  \addplot+[mark=none, forget plot] table {\datatable};
  \addplot+[only marks] table  {\datatable}
    % pos = (index-1)/(N-1)  (index starting from 1)
    node[pos=(1-1)/(\N-1), pin=right:first point (1/\N)]{}
    node[pos=(3-1)/(\N-1), pin=-45:third point (3/\N)]{}
    node[pos=(4-1)/(\N-1), pin=-45:end of linear behaviour (4/\N)]{}
;
\end{axis}
\end{tikzpicture}
\end{document}

enter image description here

  • Do you want to label just the nth point, or every nth point? For example, do you want to label just point number 2, or also points 4, 6, 8...? – Jake Jul 14 '14 at 10:17
  • just the nth point, possibly an arbitrary number of points, specified by their line number / index, e.g. (1, 2, 5). – Hotschke Jul 14 '14 at 10:17
11

I think the easiest way to do it is as you've done, keeping in mind that if there are N equally spaced points, the pos-ition of the n-th point is (n-1)/(N-1).

In your case you have 5 points and you want to mark the second, so it should be at position 0.25:

\documentclass{standalone}

\usepackage{pgfplots}
\usepackage{pgfplotstable} % For \pgfplotstableread

\pgfplotstableread{
0.01    1.00
0.02    2.00
0.03    3.00
0.04    4.00
0.05    5.00
}\datatable

\begin{document}
\begin{tikzpicture}
\begin{axis}[ymin=0, ymax=6]
\addplot table  {\datatable}
node[pos=0.0, pin=right:``first point'']{} 
node[pos=0.25, pin=above:``second point'']{} 
node[pos=1.0, pin=left:``last point'']{} 
;

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

sample code output

This will work as along as your points are evenly spaced. If they are not, you have two choices that I know of:

  1. calculate the relative position based on the point coordinates. If they are labeled x_1, x_2, ..., x_N, the n-th point is at position (x_n - x_1)/(x_N - x_1).

  2. Use a plot handler that only plots the points without interpolation, e.g., only marks. Then you can use fractional positions and the handler will “snap to” the point indexed by that fraction. So if there are five points pos=0.25 will snap to the second point regardless of whether it is really 1/4th of the way from the left to right.

If you have unevenly spaced points and you want to mark them, interpolate them, and label them, you can use a two-step approach. First, plot without marks with \addplot+[mark=none,forget plot] ... Then plot only marks and label with \addplot+[only marks] ... node[pos=0.25] .... Here is an example of that:

\documentclass{standalone}
\usepackage{pgfplots}
\pgfplotsset{compat=1.8}
\begin{document}

\begin{tikzpicture}[
    declare function={
        f(\x) = 2*(\x)^3 - 3*(\x)^2 - 12 *\x;
    }]
    \begin{axis}[
        width=\linewidth,
        xmin=-3.3,xmax=4,
        ymin=-21,ymax=21,
        xtick={-1,0.5,2},
        xticklabels={$-1$,$\frac12$,$2$},
        ytick=\empty,
        samples=50
    ]
        \addplot+[domain=-3:4,mark=none,forget plot] {f(x)};
        \addplot+[samples at={-1.8117,-1,0,0.5,2,3.3117},only marks] {f(x)}
            node[pos=0,
                pin={-88:$\left(\frac{1}{4}\left(3 - \sqrt{105}\right),0\right)$},
                ] {}
            node[pos=0.2,pin={$(-1,7)$}] {}
            node[pos=0.4,pin={15:$(0,0)$}] {}
            node[pos=0.6,pin={0:$\left(\frac12,-6\frac12\right)$}] {}
            node[pos=0.8,pin={90:$(2,-20)$}] {}
            node[pos=1.0,pin={95:$\left(\frac{1}{4}\left(3 + \sqrt{105}\right),0\right)$}] {}
        ;
    \end{axis}
\end{tikzpicture}
\end{document}

second sample code output

The forget plot command keeps the plot cycle from shifting so the second plot is styled exactly as the first one is. The second \addplot marks specific (unevenly spaced) points. Since there are six of them, the position of the n-th is 0.2n.

9

I would use the nodes near coords functionality for this, which allows you to associate the labels directly with the coordinates, regardless of the spacing. With a bit of TikZ style acrobatics, you can define a key

nodes near some coords={1,3}

that takes either a single coordinate index or a list of indices, and activates the label printing only for those coordinates:

\documentclass{standalone}

\usepackage{pgfplots}
\usepackage{pgfplotstable} % For \pgfplotstableread
\pgfplotsset{compat=1.10}

\pgfplotsset{
    node near coord/.style={ % Style for activating the label for a single coordinate
        nodes near coords*={
            \ifnum\coordindex=#1\pgfmathprintnumber{\pgfplotspointmeta}\fi
        }
    },
    nodes near some coords/.style={ % Style for activating the label for a list of coordinates
        scatter/@pre marker code/.code={},% Reset the default scatter style, so we don't get coloured markers
        scatter/@post marker code/.code={},% 
        node near coord/.list={#1} % Run "node near coord" once for every element in the list
    }
}

\pgfplotstableread{
0.01    1.00
0.02    2.00
0.024    3.00
0.04    4.00
0.05    5.00
}\datatable

\begin{document}
\begin{tikzpicture}
\begin{axis}[ymin=0, ymax=6, every node near coord/.style=above left]
\addplot +[
    nodes near some coords=0
] table {\datatable};

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

The same approach can also be used to supply the label to be printed for each coordinate, and the desired alignment.

Calling

\addplot +[
    nodes near some coords={1/Bragg valley/below,3/Bragg peak/above}
] table {\datatable};

will yield the following:

\documentclass{standalone}

\usepackage{pgfplots}
\usepackage{pgfplotstable} % For \pgfplotstableread

\pgfplotsset{
    node near coord/.style args={#1/#2/#3}{% Style for activating the label for a single coordinate
        nodes near coords*={
            \ifnum\coordindex=#1 #2\fi
        },
        scatter/@pre marker code/.append code={
            \ifnum\coordindex=#1 \pgfplotsset{every node near coord/.append style=#3}\fi
        }
    },
    nodes near some coords/.style={ % Style for activating the label for a list of coordinates
        scatter/@pre marker code/.code={},% Reset the default scatter style, so we don't get coloured markers
        scatter/@post marker code/.code={},% 
        node near coord/.list={#1} % Run "node near coord" once for every element in the list
    }
}

\pgfplotstableread{
0.01    3.00
0.02    2.00
0.024    3.00
0.04    4.00
0.05    1.00
}\datatable

\begin{document}
\begin{tikzpicture}
\begin{axis}[ymin=0, ymax=6, every node near coord/.style=above left]
\addplot +[
    nodes near some coords={1/Bragg valley/below,3/Bragg peak/above}
] table {\datatable};

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

If you want to use pins, you can use a slightly altered (and slightly more elegant) version of the approach:

\documentclass{standalone}

\usepackage{pgfplots}
\usepackage{pgfplotstable} % For \pgfplotstableread

\pgfplotsset{
    pin near coord/.style args={#1/#2}{% Style for activating the label for a single coordinate
        scatter/@pre marker code/.append code={
            \ifnum\coordindex=#1 \node[pin=#2]{};\fi
        }
    },
    pins near some coords/.style={ % Style for activating the label for a list of coordinates
        scatter,
        scatter/@pre marker code/.code={},% Reset the default scatter style, so we don't get coloured markers
        scatter/@post marker code/.code={},% 
        pin near coord/.list={#1} % Run "pin near coord" once for every element in the list
    }
}

\pgfplotstableread{
0.01    3.00
0.02    2.00
0.024    3.00
0.04    4.00
0.05    1.00
}\datatable

\begin{document}
\begin{tikzpicture}
\begin{axis}[ymin=0, ymax=6, every node near coord/.style=above left]
\addplot +[
    pins near some coords={1/south:Bragg valley,3/Bragg peak}
] table {\datatable};

\end{axis}
\end{tikzpicture}
\end{document}
  • node near coord is something I should learn more about. Would there be a way to specify the point meta in the table and display it automagically? – Matthew Leingang Jul 14 '14 at 19:13
  • I'd like to use a custom label text, not the index or the value. Is this also possible with node near coord? – Hotschke Jul 15 '14 at 8:08
  • @Hotschke: Is the label text different for each data point? If yes, how do you want to specify it: in an extra column in the table, or in the list of coordinates? – Jake Jul 15 '14 at 8:16
  • @MatthewLeingang: Yes, that's possible. You can add a column to the table that contains the meta value or text, and then use \addplot table [meta index=<column number>] ..., for instance. – Jake Jul 15 '14 at 8:17
  • 1
    @Hotschke: Quite obviously the more compact "user side" code. The "setup" is limited to the one \pgfplotsset block. – Jake Jul 15 '14 at 10:17

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.