5

I am trying to create notched box plots similar to those shown in the picture from data files. enter image description here

I have managed code that creates the box plots with notches like I want (the code below without the axis and addplot commands), but am having trouble adding axes. My setup for drawing the box plots does not work when I use \addplot and if I don't use \addplot I get other errors or depending on how I move the code for my axis, I get only the axes. I cannot think how to fix this.

\documentclass{article}
\usepackage{pgfplots}
\usepackage{filecontents}
\usepackage{pgfplotstable}
\usetikzlibrary{calc}
\begin{document}
\begin{filecontents}{boxplot.dat}
1 1 1.2 0.4 1.5 0.2 1.05 0.95
2 2 2.3 1.5 2.7 1 2.05 1.95
3 0.7 1.4 0.5 1.9 0.1 0.75 0.65
4 0.7 1.4 0.5 1.9 0.1 0.75 0.65
\end{filecontents}
\pgfplotstableread{boxplot.dat}{\infotable}
\pgfplotstablegetrowsof{boxplot.dat}
\pgfmathsetmacro{\rows}{\pgfplotsretval-1}
\begin{tikzpicture}
\begin{axis}[
xticklabels={1, 2, 3, 4},
]
\addplot{
\foreach \i in {0,...,\rows}{%
%x-values
\pgfplotstablegetelem{\i}{[index] 0}\of{\infotable}
%Middle
\let\xM\pgfplotsretval
%Left
\pgfmathsetmacro{\xL}{\xM-0.25}
\pgfmathsetmacro{\xLInd}{\xM-0.125}
%Right
\pgfmathsetmacro{\xR}{\xM+0.25}
\pgfmathsetmacro{\xRInd}{\xM+0.125}
%y-values
\pgfplotstablegetelem{\i}{[index] 4}\of{\infotable}
\let\yTopWhisk\pgfplotsretval
\pgfplotstablegetelem{\i}{[index] 2}\of{\infotable}
\let\yBoxTop\pgfplotsretval
\pgfplotstablegetelem{\i}{[index] 6}\of{\infotable}
\let\yTopInd\pgfplotsretval
\pgfplotstablegetelem{\i}{[index] 1}\of{\infotable}
\let\yMedian\pgfplotsretval
\pgfplotstablegetelem{\i}{[index] 7}\of{\infotable}
\let\yBottomInd\pgfplotsretval
\pgfplotstablegetelem{\i}{[index] 3}\of{\infotable}
\let\yBoxBottom\pgfplotsretval
\pgfplotstablegetelem{\i}{[index] 5}\of{\infotable}
\let\yBottomWhisk\pgfplotsretval
%top part
\draw [blue] (\xLInd,\yMedian) -- (\xL,\yTopInd) -- (\xL,\yBoxTop) -- (\xR,\yBoxTop) --       (\xR,\yTopInd) -- (\xRInd,\yMedian);
%bottom part
\draw [blue] (\xLInd,\yMedian) -- (\xL,\yBottomInd) -- (\xL,\yBoxBottom) -- (\xR,\yBoxBottom) -- (\xR,\yBottomInd) -- (\xRInd,\yMedian);
%median
\draw [red] (\xLInd,\yMedian) -- (\xRInd,\yMedian);
%top whisker
\draw [black] (\xM,\yBoxTop) -- (\xM,\yTopWhisk);
\draw [black] (\xL,\yTopWhisk) -- (\xR,\yTopWhisk);
%bottom whisker
\draw [black] (\xM,\yBoxBottom) -- (\xM,\yBottomWhisk);
\draw [black] (\xL,\yBottomWhisk) -- (\xR,\yBottomWhisk);
}%
}
\end{axis}
\end{tikzpicture}
\end{document}

1 Answers1

4

Since version 1.8, PGFPlots can draw boxplots out of the box (pardon the pun). You can add the ability to draw notches relatively easily, and you can use the approach from Read boxplot prepared values from a table to provide the values from a table.

The above image is generated using

\pgfplotstableread{
    lw lq med  uq uw  ln  un
     5  7 8.5 9.5 10  8.0 9.0
     4  5 6.5 8.5 9.5 5.5 7.2
}\datatable

\begin{tikzpicture}
\begin{axis}[
    boxplot/draw direction=y, 
    x=2cm,
    boxplot/box extend=0.3,
    boxplot/notch width=0.5
]
  \addplot +[
        boxplot prepared from table={
        table=\datatable,
        lower whisker=lw,
        upper whisker=uw,
        lower quartile=lq,
        upper quartile=uq,
        lower notch=ln,
        upper notch=un,
        median=med
    }, boxplot prepared
 ] coordinates {(1,4)};
  \addplot +[
            boxplot prepared from table={
        table=\datatable,
        row=1,
        lower whisker=lw,
        upper whisker=uw,
        lower quartile=lq,
        upper quartile=uq,
        lower notch=ln,
        upper notch=un,
        median=med
    }, boxplot prepared
  ] coordinates {(2,11) (2,11.5)};
\end{axis}
\end{tikzpicture}

And here's the complete code:

\documentclass{article}
\usepackage{pgfplots}
\pgfplotsset{compat=1.8}
\usepgfplotslibrary{statistics}
\begin{document}

\makeatletter
\pgfplotsset{
    boxplot/lower notch/.initial=\pgfutil@empty,
    boxplot/upper notch/.initial=\pgfutil@empty,
    boxplot/notch width/.initial=0.9,
    boxplot/draw/box/.code={%
        \draw[/pgfplots/boxplot/every box/.try]
            (boxplot box cs:\pgfplotsboxplotvalue{lower quartile},0)
            -- (boxplot box cs:\pgfplotsboxplotvalue{lower notch},0)
            -- (boxplot box cs:\pgfplotsboxplotvalue{median},0.5-\pgfplotsboxplotvalue{notch width}/2)
            -- (boxplot box cs:\pgfplotsboxplotvalue{upper notch},0)
            -- (boxplot box cs:\pgfplotsboxplotvalue{upper quartile},0)
            -- (boxplot box cs:\pgfplotsboxplotvalue{upper quartile},1)
            -- (boxplot box cs:\pgfplotsboxplotvalue{upper notch},1)
            -- (boxplot box cs:\pgfplotsboxplotvalue{median},0.5+\pgfplotsboxplotvalue{notch width}/2)
            -- (boxplot box cs:\pgfplotsboxplotvalue{lower notch},1)
            -- (boxplot box cs:\pgfplotsboxplotvalue{lower quartile},1)
            -- cycle
        ;
    },%
    boxplot/draw/median/.code={%
        \draw[/pgfplots/boxplot/every median/.try]
            (boxplot box cs:\pgfplotsboxplotvalue{median},0.5-\pgfplotsboxplotvalue{notch width}/2)
            --
            (boxplot box cs:\pgfplotsboxplotvalue{median},0.5+\pgfplotsboxplotvalue{notch width}/2)
        ;
    },%
        boxplot prepared from table/.code={
        \def\tikz@plot@handler{\pgfplotsplothandlerboxplotprepared}%
        \pgfplotsset{
            /pgfplots/boxplot prepared from table/.cd,
            #1,
        }
    },
    /pgfplots/boxplot prepared from table/.cd,
        table/.code={\pgfplotstablecopy{#1}\to\boxplot@datatable},
        row/.initial=0,
        make style readable from table/.style={
            #1/.code={
                \pgfplotstablegetelem{\pgfkeysvalueof{/pgfplots/boxplot prepared from table/row}}{##1}\of\boxplot@datatable
                \pgfplotsset{boxplot/#1/.expand once={\pgfplotsretval}}
            }
        },
        make style readable from table=lower whisker,
        make style readable from table=upper whisker,
        make style readable from table=lower quartile,
        make style readable from table=upper quartile,
        make style readable from table=median,
        make style readable from table=lower notch,
        make style readable from table=upper notch
}

\pgfplotstableread{
    lw lq med  uq uw  ln  un
     5  7 8.5 9.5 10  8.0 9.0
     4  5 6.5 8.5 9.5 5.5 7.2
}\datatable

\begin{tikzpicture}
\begin{axis}[
    boxplot/draw direction=y, 
    x=2cm,
    boxplot/box extend=0.3,
    boxplot/notch width=0.5
]
  \addplot +[
        boxplot prepared from table={
        table=\datatable,
        lower whisker=lw,
        upper whisker=uw,
        lower quartile=lq,
        upper quartile=uq,
        lower notch=ln,
        upper notch=un,
        median=med
    }, boxplot prepared
 ] coordinates {(1,4)};
  \addplot +[
            boxplot prepared from table={
        table=\datatable,
        row=1,
        lower whisker=lw,
        upper whisker=uw,
        lower quartile=lq,
        upper quartile=uq,
        lower notch=ln,
        upper notch=un,
        median=med
    }, boxplot prepared
  ] coordinates {(2,11) (2,11.5)};
\end{axis}
\end{tikzpicture}

\end{document}
Jake
  • 232,450
  • 2
    Cool answer! However, the row key is never set, i.e. it is always 0. Perhaps you should make it mandatory in your custom style (which appears to be a good addition which is missing in pgfplots, by the way). – Christian Feuersänger Aug 01 '13 at 20:12