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 like to label my plots directly, i.e. without using a legend, but instead using a pin node. So far, I have added the labels with manually specified coordinates, which means trial-and-error for data plots. A better way would be to let TikZ handle the positioning, but I don't know how to access the paths of the plots. Is there a way of adding a node to a plot in pgfplots, similar to the [pos=0.5] option for normal paths? Just adding node [pos=0.5] {x} to the \addplot command does not position the node on the line, but instead at some location in the lower left of the plot area, regardless of the pos value.

MWE:

\documentclass{article}
\usepackage{pgfplots}
\begin{document}
\begin{tikzpicture}
\begin{axis}
\addplot {x^2} node [pos=0.75,pin={-10:$x^2$},inner sep=0pt] {}; % This does not position the node on the line
\addplot {1.5*x^2};
\node at (axis cs:4,16) [pin={-10:$x^2$},inner sep=0pt] {}; % This is what I want, but without calculating the coordinates by hand
\node at (axis cs:4,24) [pin={170:$1.5 x^2$},inner sep=0pt] {};
\end{axis}
\end{tikzpicture}
\end{document}

pgfplots plot with nodes annotating the lines

share|improve this question
add comment

2 Answers 2

up vote 25 down vote accepted

The current version of pgfplots (>= 1.5.1) supports this as you expected it in the first place (i.e. using node[pos=0.75]):

enter image description here

\documentclass{article}
\usepackage{pgfplots}
\begin{document}
\thispagestyle{empty}
\begin{tikzpicture}
\begin{axis}
\addplot {x^2} node [pos=0.75,pin={-10:$x^2$},inner sep=0pt] {};
\addplot {1.5*x^2} node [pos=0.75,pin={170:$1.5 x^2$},inner sep=0pt] {};
\end{axis}
\end{tikzpicture}


\begin{tikzpicture}
 \begin{axis}[
        axis y line=center,
        axis x line=middle, 
        axis on top=true,
        xmin=-7,
        xmax=7,
        ymin=-4,
        ymax=4,
        clip=false
] 

\addplot[
    mark=none,
    domain=-4:6,
    samples=80,
    red,
    thick,
] {(x<-2)*-2 + (!(x<-2) && (x<3))*x + (!(x<3)) * 3}
    node[pos=0.1,pin=135:{\color{purple}$f(x)=-2$}] {}
    node[pos=0.6,pin=135:{\color{blue}$f(x)=x$}] {}
    node[pos=0.9,pin=135:{\color{green!70!black}$f(x)=3$}] {}
;
\end{axis}
\end{tikzpicture}

\end{document}

It is available for download on http://pgfplots.sourceforge.net/

share|improve this answer
    
+1 keeps getting better! –  percusse Sep 23 '11 at 23:26
    
Just discovered: pos=... does not work correctly if coordinates are read from an unsorted table, e.g. if x = {3 4 5 1 2} (sort of...). You'll have to sort the table first. –  Christoph Feb 9 '12 at 12:04
    
@Christoph from what I understand, a plot with the provided coordinates is completely different from one with sorted coords. I would say it is expected behavior that they look different... if you think it is an error, I would be interested in a complete bug report. –  Christian Feuersänger Feb 9 '12 at 17:40
    
@Christian "does not work correctly" was probably a bad choice of words. The pos option can simply not be used for unsorted data in order to place something along the path without some trial and error. It's not a bug. –  Christoph Feb 9 '12 at 19:56
add comment

I'm very keen on seeing other people's approaches to this, but in the meantime I'll post what I came up with:

The following code defines a new tikzstyle that creates a vertical path at a specified position in the plot, intersects that line with the plot, and adds something like a glorified pin (actually a line with a label at the end, which gives finer control over the text placement than just a pin) at the intersection.

It takes three arguments:

  • The position of the vertical line, specified as a fraction of the plot width (0 is the left edge, 1 the right)
  • The position of the label relative to the intersection of the line and plot. It can be given as polar coordinates ({45:1cm}) or a relative coordinate ({0.4cm,2cm}) and has to be enclosed in curly braces.
  • The label text, or, more accurately the label code: Either just the text, or something like {[red]left:<text>} to position the label to the left of the end of the label line and colour it red.

It's not exactly what I asked for, in that it does not position the label at a given distance along the graph, but rather at a fixed horizontal distance along the plot canvas. I find this to be more of a feature than a shortcoming, though, because it allows for nice alignments of the labels. Using other paths for defining the intersections, like horizontal lines or circles instead of the vertical line, is easily possible.

\documentclass{article}
\usepackage{pgfplots}
\usetikzlibrary{intersections}

\pgfkeys{/pgfplots/linelabel/.style args={#1:#2:#3}{name path global=labelpath,execute at end plot={
\path [name path global = labelpositionline]
(rel axis cs:#1,0) --
(rel axis cs:#1,1);
\draw [help lines,text=black,inner sep=0pt,name intersections={of=labelpath and labelpositionline}] (intersection-1) -- +(#2) node [label={#3}] {};},
}}

\begin{document}
\begin{tikzpicture}
\begin{axis}

\addplot +[linelabel=0.8:{-45:0.75cm}:{[blue]right:$x^2$}] {x^2};
\addplot +[linelabel=0.8:{-.6cm,.6cm}:$1.5x^2$] {1.5*x^2};

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

enter image description here


A way of placing labels at a specified position along the plot path, based on the answer to How determine slope of straight line (with auto scale of axis) in PGF plots

Alternatively, a decoration can be used to place label nodes. The decorations.markings library allows to place a node somewhere along a path. To use the decoration in \addplot, it has to be applied it through an every path/.style, which leads to a problem with the decoration being applied to itself. Thankfully, this has been solved already: Applying a postaction to every path in TikZ.

Also, PGFplots seems to have a problem with using TikZ nodes in the decorations. This can be avoided by using \pgfnode instead, which does exactly the same as \node, but looks a bit unusual.

Here's an example where a plotlabel style is defined (based on Altermundus' idea in How to label a path drawn using tikz with \draw plot?, and adapted to work around the described problems). You specify the label with plotlabel={<rel pos along path>}{<label text>}. To change the color of the label, \color{<color name>}<label text> can be used. The plotlabel option can be used multiple times to add different labels to the same plot.

\documentclass{article}
\usepackage{pgfplots}
\usetikzlibrary{decorations.markings}
\makeatletter
\tikzset{
    nomorepostaction/.code={\let\tikz@postactions\pgfutil@empty},
    plotlabel/.style 2 args={
        every path/.append style={
            postaction={
                nomorepostaction,
                decorate,
                decoration={
                    markings,
                    mark=at position #1 with {
                        \pgftransformresetnontranslations
           \pgfsetlinewidth{0.4pt}
           \pgfsetstrokecolor{black}
           \pgfpathmoveto{\pgfpointorigin}
           \pgfpathlineto{\pgfpoint{-0.3cm}{0.6cm}}
           \pgfusepath{stroke}
           \pgftransformshift{\pgfpoint{-0.3cm}{0.6cm}}
                        \pgfnode{rectangle}{east}{#2}{}{}
                    }
                }
            }
        }
    }
}
\makeatother

\begin{document}
\begin{tikzpicture}

 \begin{axis}[
        axis y line=center,
        axis x line=middle, 
        axis on top=true,
        xmin=-7,
        xmax=7,
        ymin=-4,
        ymax=4,
        clip=false
] 

\addplot[
    mark=none,
    domain=-4:6,
    samples=80,
    red,
    thick,
    plotlabel={0.1}{\color{purple}$f(x)=-2$},
    plotlabel={0.6}{\color{blue}$f(x)=x$},
    plotlabel={0.9}{\color{green!70!black}$f(x)=3$}
] {(x<-2)*-2 + (!(x<-2) && (x<3))*x + (!(x<3)) * 3};%
\end{axis}
\end{tikzpicture}
\end{document}

plot with label

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