7

I want to add information to each column of a histogram. every node near coord is probably the best approach. It works well with bar plots but not with the histogram:

\documentclass{article}

\usepackage{pgfplots}
\pgfplotsset{compat=newest}
\usetikzlibrary{pgfplots.statistics}

\begin{document}

\begin{tikzpicture}
\begin{axis}[
ybar interval,
xticklabel=\pgfmathprintnumber\tick--\pgfmathprintnumber\nexttick,
% Code to generate labels
nodes near coords={
\pgfmathprintnumber{\pgfkeysvalueof{/data point/y}}
},
every node near coord/.style={
anchor=south,xshift=9mm,
},
%
]
\addplot+[hist={bins=3}]
table[row sep=\\,y index=0] {
data\\
1\\ 2\\ 1\\ 5\\ 4\\ 10\\
7\\ 10\\ 9\\ 8\\ 9\\ 9\\
};
\end{axis}
\end{tikzpicture}

\end{document}

I used every node near coord/.style to shift the labels.

The problem is that I have four labels for three columns/bars:

enter image description here

I addition I would like to center the labels. A workaround will be a manual adjustment (every node near coord/.style) just like in the shown example.

Update

Maybe clipping is a possibility. Is there a way to clip the labels (in this case the 7 in the right) away?

Like this:

enter image description here

  • 1
    I think this is actually a bug: nodes near coords should not generate the last item at all for ybar interval. – Christian Feuersänger Jun 8 '14 at 20:39
  • 1
    The same is probably true for the missing shift. I noted both on the todo list for pgfplots (i.e. I accept them as bug/feature requests). – Christian Feuersänger Jun 8 '14 at 20:40
5

The necessary xshift for the nodes near coords labels can be calculated from the width of the axis, the number of bins and the value of enlarge x limits (defined in the new macro \enlargexlimits).

nodes near coords*/.add code={}{\tikzset{every node/.append style={xshift={
  (\pgfkeysvalueof{/pgfplots/width}-45pt) % every plot is 45pt smaller then the width
  /(1+2*\enlargexlimits) % correction for enlarge x limits
  /\pgfkeysvalueof{/pgfplots/hist/bins} % number of bins
  /2% shift only half of bin width
}}}},

If you want clipping all stuff right of the plot box you can fill this area with your page color and recalculate the bounding box of the whole plot.

Therefore I define a macro

\newcommand\clipright[1][white]{
  \fill[#1](current axis.south east)rectangle(current axis.north-|current axis.outer east);
  \pgfresetboundingbox
  \useasboundingbox(current axis.outer south west)rectangle(current axis.outer north-|current axis.east);
}

and a second macro to show the resulting boundig box of the plot

\newcommand\showbb{
  \draw[red,dashed](current bounding box.south west)rectangle(current bounding box.north east);
}

enter image description here

\documentclass[margin=5mm]{standalone}

\usepackage{pgfplots}
\pgfplotsset{compat=newest} % notice: version 1.10 or later is needed

\newcommand*\enlargexlimits{.1} % default value for enlarge x limits 

\pgfplotsset{%
  hist nodes near coords/.style={%
    nodes near coords*/.add code={}{\tikzset{every node/.append style={xshift={
      (\pgfkeysvalueof{/pgfplots/width}-45pt) % every plot is 45pt smaller then the width
      /(1+2*\enlargexlimits) % correction for enlarge x limits
      /\pgfkeysvalueof{/pgfplots/hist/bins} % number of bins
      /2% shift only half of bin width
    }}}},
    nodes near coords={%
      \pgfmathprintnumber{\pgfkeysvalueof{/data point/y}}
    }}
}

\newcommand\clipright[1][white]{
  \fill[#1](current axis.south east)rectangle(current axis.north-|current axis.outer east);
  \pgfresetboundingbox
  \useasboundingbox(current axis.outer south west)rectangle(current axis.outer north-|current axis.east);
}

\newcommand\showbb{
  \draw[red,dashed](current bounding box.south west)rectangle(current bounding box.north east);
}

\begin{document}

\begin{tikzpicture}

  \begin{axis}[
    ybar interval,
    xticklabel=\pgfmathprintnumber\tick--\pgfmathprintnumber\nexttick,
    enlarge x limits=\enlargexlimits
  ]
    \addplot+[hist={bins=3},hist nodes near coords]
      table[row sep=\\,y index=0] {
      data\\
      1\\ 2\\ 1\\ 5\\ 4\\ 10\\
      7\\ 10\\ 9\\ 8\\ 9\\ 9\\
    };
  \end{axis}
  \clipright
  \showbb
\end{tikzpicture}
\end{document}

But there will be a problem if you increase the number of bins. Here is the result of bin=9:

enter image description here

To solve this you can decrease the enlarge x limits by redefining the macro \enlargexlimits

\begin{tikzpicture}
  \def\enlargexlimits{0.04} % changing the value of `enlarge x limits`
  \begin{axis}[
    ybar interval,
    xticklabel=\pgfmathprintnumber\tick--\pgfmathprintnumber\nexttick,
    enlarge x limits=\enlargexlimits
  ]

Then you will get

enter image description here

Or with \def\enlargexlimits{0} you will get

enter image description here

Note: the labels are again automatically centered.


My former suggestion

To supress the additional label the pgfmath if-then-else function is used. The syntax is x ? y : z meaning " if x then y else z "

\documentclass{article}

\usepackage{pgfplots}
\pgfplotsset{compat=newest} % notice: version 1.10 or later is needed

\newcommand*\NNC{\pgfmathprintnumber{\pgfkeysvalueof{/data point/y}}}
\newcommand*\enlargexlimits{.1} % default value for enlarge x limits 

\pgfplotsset{%
  hist nodes near coords/.style={%
    nodes near coords*/.add code={}{\tikzset{every node/.append style={xshift={
      (\pgfkeysvalueof{/pgfplots/width}-45pt) % every plot is 45pt smaller then the width
      /(1+2*\enlargexlimits) % correction for enlarge x limits
      /\pgfkeysvalueof{/pgfplots/hist/bins} % number of bins
      /2% shift only half of bin width
    }}}},
    nodes near coords={% 
      \pgfmathparse{
        \pgfkeysvalueof{/data point/x}<#1*\pgfkeysvalueof{/pgfplots/hist/data max}?%
          "\noexpand\NNC"%  if true print nodes near coords
          :% if false suppress the additional node near coords
      }\pgfmathresult%
    }},
  hist nodes near coords/.default={0.9}% if you set data max explicitly it will be 1
}

\begin{document}

\begin{tikzpicture}
  \begin{axis}[
    ybar interval,
    xticklabel=\pgfmathprintnumber\tick--\pgfmathprintnumber\nexttick,
    enlarge x limits=\enlargexlimits
  ]
    \addplot+[hist={bins=3},hist nodes near coords]
      table[row sep=\\,y index=0] {
      data\\
      1\\ 2\\ 1\\ 5\\ 4\\ 10\\
      7\\ 10\\ 9\\ 8\\ 9\\ 9\\
    };
  \end{axis}
\end{tikzpicture}
\begin{tikzpicture}
  \begin{axis}[
    ybar interval,
    xticklabel=\pgfmathprintnumber\tick--\pgfmathprintnumber\nexttick,
    enlarge x limits=\enlargexlimits
  ]
    \addplot+[hist={bins=2},hist nodes near coords]
      table[row sep=\\,y index=0] {
      data\\
      1\\ 2\\ 1\\ 5\\ 4\\ 10\\
      7\\ 10\\ 9\\ 8\\ 9\\ 9\\
    };
  \end{axis}
\end{tikzpicture}

\end{document}

enter image description here

  • Thanks. What's the main idea? Some kinf of if-then-else? – Dr. Manuel Kuehner May 29 '14 at 23:20
  • Yes, I use a pgfmath if-then-else function with syntax x ? y : z meaning " if x then y else z " – esdd May 30 '14 at 6:51
  • Ok. Thanks! (Danke :) I want to wait a bit - maybe another solution is also possible. – Dr. Manuel Kuehner May 30 '14 at 10:55
  • No problem, it would be fine if there is another and possible better solution. (In the manual (version 1.10) you can read on page 108: "Currently nodes near coords does not work satisfactorily for ybar interval or xbar interval, sorry.") – esdd May 30 '14 at 11:05
  • Didn't see that in the manual - thanks for the hint. – Dr. Manuel Kuehner May 30 '14 at 12:09
4
+25

An alternative is the use of clip command.

Sine the OP does not provide data point/y infomation, this solution uses home-made substitutes for demonstration purpose. The frame in the sectiond image is again for demonstration whch can be adjusted in the clip command. Remove preaction=draw in the clip option to remove the frame. Note clip=false is required in the solution.

enter image description here

Code

\documentclass[border=10pt,varwidth]{standalone}%{article}

\usepackage{pgfplots}
\pgfplotsset{compat=newest}
\usetikzlibrary{pgfplots.statistics}

\begin{document}

Before:

\begin{tikzpicture}
\begin{axis}[
ybar interval,
clip=false,
xticklabel=\pgfmathprintnumber\tick--\pgfmathprintnumber\nexttick,
% Code to generate labels
%nodes near coords={
%\pgfmathprintnumber{\pgfkeysvalueof{/data point/y}}
%},
nodes near coords={\pgfmathprintnumber\pgfplotspointmeta\%},
every node near coord/.style={
anchor=south,xshift=9mm,
},
%
]
\begin{scope}
\addplot+[hist={bins=3}]
table[row sep=\\,y index=0] {
data\\
1\\ 2\\ 1\\ 5\\ 4\\ 10\\
7\\ 10\\ 9\\ 8\\ 9\\ 9\\
};
\end{scope}
\end{axis}
\end{tikzpicture}

After:

\begin{tikzpicture}
\begin{axis}[
ybar interval,
clip=false,
xticklabel=\pgfmathprintnumber\tick--\pgfmathprintnumber\nexttick,
% Code to generate labels
%nodes near coords={
%\pgfmathprintnumber{\pgfkeysvalueof{/data point/y}}
%},
nodes near coords={\pgfmathprintnumber\pgfplotspointmeta\%},
every node near coord/.style={
anchor=south,xshift=9mm,
},
%
]
\begin{scope}
\clip[preaction=draw] (axis cs: -1,-0.1) rectangle (axis cs:11,8);  % remove preaction=draw to remove the frame
\addplot+[hist={bins=3}]
table[row sep=\\,y index=0] {
data\\
1\\ 2\\ 1\\ 5\\ 4\\ 10\\
7\\ 10\\ 9\\ 8\\ 9\\ 9\\
};
\end{scope}
\end{axis}
\end{tikzpicture}

\end{document}
  • Which version of pgfplots do you have? Your code works for me if I install version 1.8 in my local tree. But it does not work if I use version 1.9 or 1.10 even if I say compat=1.8. – esdd Jun 3 '14 at 8:55
  • Indeed, mine is 1.8. – Jesse Jun 3 '14 at 10:24
  • That is also the reason why nodes near coords={\pgfmathprintnumber{\pgfkeysvalueof{/data point/y}}} does not work for you. To get the abundances automatically version 1.10 is needed. – esdd Jun 3 '14 at 10:30
  • Thanks for the solution. So the key is scope and the clip command?! – Dr. Manuel Kuehner Jun 4 '14 at 8:52
  • 1
    No, I am afraid not. I did tried it. Further your code does not work for version 1.8. So IMHO there is a backward/forward compatibility between these two versions. I also notice that the other answer requires 1.10 or later. With that informed, I keep two versions. – Jesse Jun 5 '14 at 13:54

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.