# How to make barplots with text above the bars that always will be inside the axes?

I am making bar plots (xbar) in pgfplots and adding text/numbers on top of each bar by using the nodes near coords command in the axis environment. The x-axis is by purpose not given any value for the parameter xmax in order to make the tallest bar dynamically determine the maximum x-value used in the axis (the line xmax=100 is commented out). However, the extent of the text/numbers on top of each bar is not taken into account when the max value along the x-axis is determined by TikZ. In my example, the name "Steve" on top of the second bar from above is overlapping with the right y-axis. How do I prevent this in a way that will fix the problem independently of the x values in the data.dat file?

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

\begin{filecontents}{data.dat}
Age-interval        Y-Position         Score        Name
20-30               1                  15           Peter
30-40               2                  98           Jeff
40-50               3                  121          Steve
50-60               4                  24           John
\end{filecontents}

\begin{document}
\begin{tikzpicture}

\makeatletter
\begin{axis}[
xlabel={Test score},
xbar,
bar width=2pt,
ytick=data,
width=8 cm,
height=5 cm,
xmin=-1,
% xmax = 100,
xticklabel pos = upper,
tick align = outside,
yticklabel pos=left,
yticklabels from table={data.dat}{Age-interval},
ylabel={Age intervals (yr)},
nodes near coords,
every node near coord/.append style={anchor=west},
point meta=explicit symbolic
]
y=Y-Position,
x=Score,
meta=Name
] {data.dat};
\end{axis}

\end{tikzpicture}
\end{document}


-

You can set enlarge x limits={upper, value=0.2}, which will increase the upper x limit by 20% of the plot's x range, so as long as none of your labels are wider than 20% of the plot width, you should be fine. If you have longer labels, you might need to choose a different value.

If you really want an automatic solution that will accommodate any label length, here's one solution. I wrote a new key called accommodate labels that takes the name of a table and the name of a column containing the labels as arguments, and then computes the enlarge x limits value. This assumes that the width of the plot is set manually (otherwise the value is not available), and that scale only axis is activated (otherwise the width refers to the whole figure, not just the axis area).

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

\begin{filecontents}{data.dat}
Age-interval        Y-Position         Score        Name
20-30               1                  15           Peter
30-40               2                  98           Jeff
40-50               3                  121          LoooooooongJohnSilver
50-60               4                  24           John
\end{filecontents}

\pgfplotsset{
accommodate labels/.code 2 args={
\newlength{\myl}
\def\largestlength{0}
\pgfplotstableforeachcolumnelement{#2}\of\data\as\cell{
\settowidth{\myl}{\pgfinterruptpicture\cell\endpgfinterruptpicture}
\pgfmathsetmacro\largestlength{max(\the\myl,\largestlength)}
}
\pgfplotsset{
enlarge x limits={
upper,              value=1/(1-(\largestlength+4pt)/\pgfkeysvalueof{/pgfplots/width})-1
}
}
}
}

\begin{document}

\begin{tikzpicture}
\begin{axis}[
xlabel={Test score},
xbar,
bar width=2pt,
ytick=data,scale only axis,
width=6cm,
height=5cm,
xmin=-1,
accommodate labels={data.dat}{Name},
xticklabel pos = upper,
tick align = outside,
yticklabel pos=left,
yticklabels from table={data.dat}{Age-interval},
ylabel={Age intervals (yr)},
nodes near coords,
every node near coord/.append style={anchor=west},
point meta=explicit symbolic
]
y=Y-Position,
x=Score,
meta=Name
] {data.dat};
\end{axis}

\end{tikzpicture}
\end{document}

-
@Espen Consider removing the right y and upper x axis lines. You don't need them, as this is not a diagram where the ticks help you in accurately reading a certain value. In Jake's example, the x axis has eight labels, while you only have 4 data points. You could add the actual value to each name and get a more precise diagram that way. – Christoph Feb 17 '12 at 13:17
@Jake Thaks for your answer, it works :) But this solution is still somewhat manual. I am working on a code for automatically generating reports and would like a dynamic solution that takes care of the length of the names on top of each bar. – Espen Donali Feb 17 '12 at 13:26
@Christoph Thanks for your answer. Yes you are right in this simple expample, but my barplots are combined into larger diagrames where I need this structure. Anyhow: the names on top of the bars still may protude outside the leftmost y-axis regardless of if this axis is drawn or not. – Espen Donali Feb 17 '12 at 13:29
@EspenDonali: I've edited my answer to include a different approach. – Jake Feb 17 '12 at 15:23
@Jake thanks a lot! Your answer seems very promissing, I will test it out :) – Espen Donali Feb 17 '12 at 16:25