6

I have the following data:

[0, 1000) : 14524
[1000, 2000) : 38214
[2000, 3000) : 36169
[3000, 4000) : 25875
[4000, 5000) : 16942
[5000, 6000) : 10603
[6000, 7000) : 6778
[7000, 8000) : 4288
[8000, 9000) : 2980
[9000, 10000) : 1986
[10000, 11000) : 1392
[11000, 12000) : 1040
[12000, 13000) : 801
[13000, 14000) : 632
[14000, 15000) : 467
[15000, \infty): 3819

How can I plot such data in form of a histogram?

My Try

% Source: http://tex.stackexchange.com/a/65518/5645
\documentclass{standalone}
\usepackage{pgfplots}

\begin{document}
\begin{tikzpicture}
    \begin{axis}[/tikz/ybar,
        ybar legend,
        xtick align=outside,
        ymin=0,
        bar width=0.9cm,
        axis x line*=left,
        enlarge x limits=false,
        grid=major,
        height=7cm,
        title={All Results},
        xlabel={recording time $t$ in ms},
        ylabel={Number of Recordings},
        symbolic x coords={$0$, $1000$, $2000$, $3000$, $4000$, $5000$,
                           $6000$, $7000$, $8000$, $9000$, $10000$,
                           $11000$, $12000$, $13000$, $14000$, $15000$},
        minor x tick num=5,
        extra x tick style={xticklabel style={yshift=-15pt}},
        width=\textwidth,
        xtick=data,
        xticklabel style={
            inner sep=0pt,
            anchor=north east,
            rotate=45
        },
        nodes near coords,
        every node near coord/.append style={
            anchor=mid west,
            rotate=45}]
    \addplot[blue, fill=blue!40!white] coordinates {($0$,  14524) ($1000$,  38214) ($2000$,  36169) ($3000$,  25875) ($4000$,  16942) ($5000$,  10603) ($6000$,  6778) ($7000$,  4288) ($8000$,  2980) ($9000$,  1986) ($10000$,  1392) ($11000$,  1040) ($12000$,  801) ($13000$,  632) ($14000$,  467) ($15000$,  3819)};
    \legend{Time}
    \end{axis}
\end{tikzpicture}
\end{document}

which produces

enter image description here

My main problem is that the bins are centered around the symbolic tikz. They should be in the range noted above.

edit: Obviously I did not express myself clearly. My problem is that the labels of the first bar of the histogram seem to go from -500 to +500. But they should go from 0 to 1000

The other problems (overlapping bars, overlapping of the x-label and the x-tick labels) are not part of the question (although it would be nice if I could get pointers how to fix that).

5

My suggestion is

enter image description here

Code:

\documentclass[margin=10pt]{standalone}
\usepackage{amsmath}
\usepackage{pgfplots}
\pgfplotsset{compat=1.10}

\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([xshift=.5ex]current axis.outer north-|current axis.east);
}

\begin{document}
\begin{tikzpicture}
    \begin{axis}[/tikz/ybar interval,
        ybar legend,
        xtick align=outside,
        ymin=0,
        axis x line*=left,
        enlarge x limits=false,
        grid=major,
        height=7cm,
        title={All Results},
        xlabel={recording time $t$ in ms},
        ylabel={Number of Recordings},
        xtick={0,...,16},
        xticklabels={$0$, $1000$, $2000$, $3000$, $4000$, $5000$,
                           $6000$, $7000$, $8000$, $9000$, $10000$,
                           $11000$, $12000$, $13000$, $14000$, $15000$,$\infty$},
        width=\textwidth,
        xtick=data,
        xticklabel style={
            inner sep=0pt,
            anchor=north east,
            rotate=45
        },
        nodes near coords,
        every node near coord/.append style={
            anchor=mid west,
            rotate=45},
            ]
    \addplot[blue, fill=blue!40!white] coordinates {(0,  14524) (1,  38214) (2,  36169) (3,  25875) (4,  16942) (5,  10603) (6,  6778) (7,  4288) (8,  2980) (9,  1986) (10,  1392) (11,  1040) (12,  801) (13,  632) (14,  467) (15,  3819) (16,  3819)};
    \legend{Time}
    \end{axis}
    \clipright
\end{tikzpicture}
\end{document}

Explanation:

Your main problem can be solved by using /tikz/ybar interval instead /tikz/ybar. In addition it is necessary to set the compat option at least to 1.3 to avoid the overlapping of xlabel and xtick labels automatically. The current pgfplots version is 1.10.

enter image description here

Code:

\documentclass[margin=10pt]{standalone}
\usepackage{pgfplots}
\pgfplotsset{compat=1.3}

\begin{document}
\begin{tikzpicture}
    \begin{axis}[
        /tikz/ybar interval,
        ybar legend,
        xtick align=outside,
        ymin=0,
        %bar width=0.9cm,
        axis x line*=left,
        enlarge x limits=false,
        grid=major,
        height=7cm,
        title={All Results},
        xlabel={recording time $t$ in ms},
        ylabel={Number of Recordings},
        symbolic x coords={$0$, $1000$, $2000$, $3000$, $4000$, $5000$,
                           $6000$, $7000$, $8000$, $9000$, $10000$,
                           $11000$, $12000$, $13000$, $14000$, $15000$},
        %minor x tick num=5,
        %extra x tick style={xticklabel style={yshift=-15pt}},
        width=\textwidth,
        xtick=data,
        xticklabel style={
            inner sep=0pt,
            anchor=north east,
            rotate=45
        },
        nodes near coords,
        every node near coord/.append style={
            anchor=mid west,
            rotate=45}]
    \addplot[blue, fill=blue!40!white] coordinates {($0$,  14524) ($1000$,  38214) ($2000$,  36169) ($3000$,  25875) ($4000$,  16942) ($5000$,  10603) ($6000$,  6778) ($7000$,  4288) ($8000$,  2980) ($9000$,  1986) ($10000$,  1392) ($11000$,  1040) ($12000$,  801) ($13000$,  632) ($14000$,  467) ($15000$,  3819)};
    \legend{Time}
    \end{axis}
\end{tikzpicture}
\end{document}

But there are some other problems: The last item is missing. This behavoir is explained in the manual. And in addition there is a known issue: nodes near coords generates the last item outside the axis. To solve this problems you can add an additional coordinate (infinite, 3819) and use the workaround from this question:

enter image description here

\documentclass[margin=10pt]{standalone}
\usepackage{pgfplots}
\pgfplotsset{compat=1.10}

\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([xshift=.5ex]current axis.outer north-|current axis.east);
}

\begin{document}
\begin{tikzpicture}
    \begin{axis}[
        /tikz/ybar interval,
        ybar legend,
        xtick align=outside,
        ymin=0,
        axis x line*=left,
        enlarge x limits=false,
        grid=major,
        height=7cm,
        title={All Results},
        xlabel={recording time $t$ in ms},
        ylabel={Number of Recordings},
        symbolic x coords={$0$, $1000$, $2000$, $3000$, $4000$, $5000$,
                           $6000$, $7000$, $8000$, $9000$, $10000$,
                           $11000$, $12000$, $13000$, $14000$, $15000$, infinite},
        width=\textwidth,
        xtick=data,
        xticklabel style={
            inner sep=0pt,
            anchor=north east,
            rotate=45
        },
        nodes near coords,
        every node near coord/.append style={
            anchor=mid west,
            rotate=45}]
    \addplot[blue, fill=blue!40!white] coordinates {($0$,  14524) ($1000$,  38214) ($2000$,  36169) ($3000$,  25875) ($4000$,  16942) ($5000$,  10603) ($6000$,  6778) ($7000$,  4288) ($8000$,  2980) ($9000$,  1986) ($10000$,  1392) ($11000$,  1040) ($12000$,  801) ($13000$,  632) ($14000$,  467) ($15000$,  3819) (infinite,  3819)};
    \legend{Time}
    \end{axis}
    \clipright
\end{tikzpicture}
\end{document}

Unfortunately I wasn't able to use \infty as a symbolic coordinate without getting error messages.

But it works if I use xtick={1,...,16} and xticklabels instead of symbolic x coords. Then I must change the coordinates to

\addplot[blue, fill=blue!40!white] coordinates {(0,  14524) (1,  38214) (2,  36169) (3,  25875) (4,  16942) (5,  10603) (6,  6778) (7,  4288) (8,  2980) (9,  1986) (10,  1392) (11,  1040) (12,  801) (13,  632) (14,  467) (15,  3819) (16,  3819)};

or use a table

\addplot[blue, fill=blue!40!white] table[x expr=\coordindex,y expr=\thisrowno{0},row sep=\\,header=false]{14524\\ 38214\\ 36169\\ 25875\\ 16942\\ 10603\\ 6778\\ 4288\\ 2980\\ 1986\\ 1392\\ 1040\\ 801\\ 632\\ 467\\ 3819\\ 3819\\};

The result is shown at the top of my answer.

7

I shamelessly stole from esdd's answer and just changed the design a little bit to make it look less cluttered. enter image description here

\documentclass[margin=10pt]{standalone}
\usepackage{amsmath}
\usepackage{pgfplots}
\pgfplotsset{compat=1.3}

\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([xshift=.5ex]current axis.outer north-|current axis.east);
}

\definecolor{mycolor}{rgb}{0.02,0.4,0.7}

\begin{document}
\begin{tikzpicture}
    \begin{axis}[
        ymajorgrids,
        xmajorgrids,
        grid style={white,thick},
        axis on top,
        /tikz/ybar interval,
        tick align=outside,
        ymin=0,
        axis line style={draw opacity=0},
        tick style={draw=none},
        enlarge x limits=false,
        height=7cm,
        title={All Results},
        title style={font=\Large},
        xlabel={recording time $t$ in s},
        ylabel={Number of Recordings},
        ytick={0,10000,20000,30000,40000},
        scaled ticks=false,
        yticklabels={0,10k,20k,30k,40k},
        xticklabels={$0$, $1$, $2$, $3$, $4$, $5$,
                           $6$, $7$, $8$, $9$, $10$,
                           $11$, $12$, $13$, $14$, $15$,$\infty$},
        width=\textwidth,
        xtick=data,
        label style={font=\large},
        ticklabel style={
            inner sep=1pt,
            font=\small
        },
        nodes near coords,
        every node near coord/.append style={
            fill=white,
            anchor=mid west,    
            shift={(3pt,4pt)},
            inner sep=0,
            font=\footnotesize,
            rotate=45},
            ]
    \addplot[mycolor!80!white, fill=mycolor, draw=none] coordinates {(0,  14524) (1,  38214) (2,  36169) (3,  25875) (4,  16942) (5,  10603) (6,  6778) (7,  4288) (8,  2980) (9,  1986) (10,  1392) (11,  1040) (12,  801) (13,  632) (14,  467) (15,  3819) (16,  0)};
    \end{axis}
    \clipright
\end{tikzpicture}
\end{document}
  • 1
    Thank you! It looks beautiful. It took me a few hours to automate the changes that you made, but now it's part of github.com/MartinThoma/LaTeX-examples/tree/master/tikz/… . As your answer didn't get the upvotes it deserves, I've added a bounty (but I have to wait 24h until I can give it to you). – Martin Thoma Aug 6 '14 at 15:20
  • Nicely done in Tufte style! – Roald Sep 18 '16 at 19:51
3

If I understand it correctly the histogram bins are overlapping and you want to fix that. My solution is to adjust spacing of each symbolic coordinate rather than adjusting the bin width.

One solution is to use the x=<dimension> key. It requires some fiddling around with the appropriate dimension; most histograms in fact don't use this compact way of showing histograms but leave some space in between.

Regardless, I've added it to the example below, along with a picture. (Small edit: it appears your last bar was left out in the last plot, so I've fixed that with the key enlarge x limits={true,value=.04}, which enlarges the x limits by 4% on both sides. Picture updated as well.)

enter image description here

% Source: http://tex.stackexchange.com/a/65518/5645
\documentclass{standalone}
\usepackage{pgfplots}
\pgfplotsset{compat=newest}

\begin{document}
\begin{tikzpicture}
    \begin{axis}[/tikz/ybar,
        ybar legend,
        xtick align=outside,
        bar width=0.9cm,
        axis x line*=left,
        enlarge x limits=false,
        grid=major,
        height=7cm,
        title={All Results},
        xlabel={recording time $t$ in ms},
        ylabel={Number of Recordings},
        symbolic x coords={$0$, $1000$, $2000$, $3000$, $4000$, $5000$,
                           $6000$, $7000$, $8000$, $9000$, $10000$,
                           $11000$, $12000$, $13000$, $14000$, $15000$},
        minor x tick num=5,
        extra x tick style={xticklabel style={yshift=-15pt}},
        width=\textwidth,
        xtick=data,
        x=.9cm,
        enlarge x limits={true,value=.04},
        xticklabel style={
            inner sep=0pt,
            anchor=north east,
            rotate=45
        },
        nodes near coords,
        every node near coord/.append style={
            anchor=east,
            rotate=45,
            xshift=40pt
            }]
    \addplot[blue, fill=blue!40!white] coordinates {($0$,  14524) ($1000$,  38214) ($2000$,  36169) ($3000$,  25875) ($4000$,  16942) ($5000$,  10603) ($6000$,  6778) ($7000$,  4288) ($8000$,  2980) ($9000$,  1986) ($10000$,  1392) ($11000$,  1040) ($12000$,  801) ($13000$,  632) ($14000$,  467) ($15000$,  3819) };
    \legend{Time}
    \end{axis}
\end{tikzpicture}
\end{document}

If you don't feel like fiddling around with dimensions, use the ybar interval key. It produces pretty much the same result, minus some small spacing differences about the numbers above the bins.

EDIT: this style apparently requires a begin and an end point, which causes the last bar to not be drawn (while the symbolic x-coordinate will be drawn regardless because it's not a numerical value :-(). I'll look into a solution later today.

enter image description here

% Source: http://tex.stackexchange.com/a/65518/5645
\documentclass{standalone}
\usepackage{pgfplots}
\pgfplotsset{compat=newest}

\begin{document}
\begin{tikzpicture}
    \begin{axis}[/tikz/ybar,
        ybar legend,
        xtick align=outside,
        ymin=0,
        bar width=0.9cm,
        axis x line*=left,
        enlarge x limits=false,
        grid=major,
        height=7cm,
        title={All Results},
        xlabel={recording time $t$ in ms},
        ylabel={Number of Recordings},
        symbolic x coords={$0$, $1000$, $2000$, $3000$, $4000$, $5000$,
                           $6000$, $7000$, $8000$, $9000$, $10000$,
                           $11000$, $12000$, $13000$, $14000$, $15000$},
        minor x tick num=5,
        extra x tick style={xticklabel style={yshift=-15pt}},
        width=\textwidth,
        xtick=data,
        ybar interval,
        xticklabel style={
            inner sep=0pt,
            anchor=north east,
            rotate=45
        },
        nodes near coords,
        every node near coord/.append style={
            anchor=mid west,
            rotate=45}]
    \addplot[blue, fill=blue!40!white] coordinates {($0$,  14524) ($1000$,  38214) ($2000$,  36169) ($3000$,  25875) ($4000$,  16942) ($5000$,  10603) ($6000$,  6778) ($7000$,  4288) ($8000$,  2980) ($9000$,  1986) ($10000$,  1392) ($11000$,  1040) ($12000$,  801) ($13000$,  632) ($14000$,  467) ($15000$,  3819)};
    \legend{Time}
    \end{axis}
\end{tikzpicture}
\end{document}
  • I am sorry for not clearly expressing my problem. I wanted to fix the labels of the x-axis (recording time t in ms). They should be for the first bar from 0 to 1000, not from -500 to +500 as it also is the case in your image. – Martin Thoma Aug 5 '14 at 12:08

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.