2

I have my own custom style for boxplots which I like very much. I like it so much I would like to use it everywhere. I used it with the old boxplots, and it did everything I wanted.

However, the style is broken with the new style of boxplots. Specifically, I like to use mark=x for my outliers, and this gets ignored by the new code.

Exploring the code of pgfplots.statistics (the library that defines the boxplot code), I realised that there is a \pgfplots@boxplot@ensure@plot@mark macro that 1) checks the value of \ifpgfplots@boxplot@ensure@plot@mark and (if true?) resets the mark (ie, mark=*).

Later, this if is assigned to a handler called boxplots/ensure mark, with a rather cryptic remark:

% mainly used for compatibility.
boxplot/ensure mark/.is if=pgfplots@boxplot@ensure@plot@mark,

Now, I like compatibility as much as the next guy, but I like my boxplot style better, and I like to live on the edge, so I'm looking for ways to revert this and damn the consequences. (Incidentally, if someone can explain to me what those consequences might be, I'd be much obliged).

I've tried doing

\makeatletter
\pgfplots@boxplot@ensure@plot@markfalse
\makeatother

in my preamble, but no go.

I've tried

\pgfplotsset{
  boxplot/ensure mark=false,
}

but that did nothing either.

The only way I can actually force my own mark, is by repeating the mark=x line after the boxplot has been called. This does work, but I want to know if there's a better solution. Specially considering there seems to be a toggle for this very task.

Here's the MWE:

\documentclass{article}
\usepackage{pgfplots}
\usetikzlibrary[pgfplots.statistics,calc]

% Tried this, didn't work
% \makeatletter
% \pgfplots@boxplot@ensure@plot@markfalse
% \makeatother

\pgfplotsset{
  compat=1.12,
  boxplot/box width/.initial=1em,
  solid boxes/.style={
    clip = false,
    solid,
    mark=x,
    boxplot/draw direction=y,
    boxplot/whisker extend=0,
    boxplot/draw/median/.code={%
      \draw[mark size=2pt,/pgfplots/boxplot/every median/.try]
        \pgfextra
        \pgftransformshift{
          \pgfplotsboxplotpointabbox
            {\pgfplotsboxplotvalue{median}}
            {0.5}
        }
        \pgfsetfillcolor{white}
        \pgfuseplotmark{*}
        \endpgfextra
      ;
    },
    boxplot/draw/box/.code={
      \draw[fill,/pgfplots/boxplot/every box/.try]
        ($(boxplot box cs:\pgfplotsboxplotvalue{lower quartile},0.5)!0.5\pgfkeysvalueof{/pgfplots/boxplot/box width}!(boxplot box cs:\pgfplotsboxplotvalue{lower quartile},0)$)
        rectangle
        ($(boxplot box cs:\pgfplotsboxplotvalue{upper quartile},0.5)!0.5\pgfkeysvalueof{/pgfplots/boxplot/box width}!(boxplot box cs:\pgfplotsboxplotvalue{upper quartile},1)$)
      ;
    }
  },
  % Tried this, didn't work
  boxplot/ensure mark/.is if=pgfplots@boxplot@ensure@plot@mark,
  boxplot/ensure mark=false,
}

\begin{document}

\begin{figure}
  \centering
  \begin{tikzpicture}
    \begin{axis}[
        xtick={1,2,3},
        xticklabels={Group A, Group B, Group C},
        % This applies the style, but the mark gets overwritten
        solid boxes,
      ]
      \addplot+[% Group A:
        boxplot prepared={
          lower whisker=42, lower quartile=45,
          median=47,
          upper quartile=47.5, upper whisker=48,
        },
      ] table[row sep=\\,y index=0] { 40\\ 34\\ 56\\ };
      \addplot+[% Group B:
        boxplot prepared={
          lower whisker=36, lower quartile=39,
          median=40,
          upper quartile=41, upper whisker=43,
        },
      ] coordinates {};
      \addplot+[% Group C:
        boxplot prepared={
          lower whisker=41, lower quartile=44,
          median=45,
          upper quartile=46, upper whisker=47,
        },
        % This works, but is not a complete solution
        mark=x,
      ] coordinates {(0,35) (0,55)};
    \end{axis}
  \end{tikzpicture}
  \caption[A caption]{A caption for my figure}
\end{figure}

\end{document}

And a picture, with helpful annotations:

The output of the MWE: a vertical boxplot with three boxes. The one on the left marks outiers with circles; the one on the right marks them with exes. The latter are labelled with a happy face.

2 Answers 2

1

Even though the question is old, I couldn't find another one solving the problem. I fiddled around a bit with the code and managed to get it to work. Specifically, I used the command

every boxplot/.style={mark=x,every mark/.append style={mark size=1.5pt}}

and it worked ;)

1
  • Just to add, to set it globally, add it to \pgfplotsset{ ...here... }. May 20, 2017 at 22:32
0

I don't know why this works, but the steps below fix the problem I had. In order to do it, I had to:

1) specify a cycle list (which does not have to specify a mark of any type: the example below uses color list, which as far as I understand only changes colours); and

2) make some changes to the style I was using so that it is plugged into every axis plot.

Combined, these two generate the desired output, shown below. The corrected MWE is at the bottom.

enter image description here

It would be nice to understand why this works, and how you can actually use \pgfplots@boxplot@ensure@plot@mark or boxplot/ensure mark to do what I imagine they are there for. But since these steps managed to do what I wanted, I'll leave them here as an answer.

\documentclass{article}
\usepackage{pgfplots}
\usetikzlibrary[pgfplots.statistics,calc]

\pgfplotsset{
  compat=1.12,
  boxplot/box width/.initial=1em,
  solid boxes/.style={
    clip = false,
    every axis plot/.style={
      solid,
      mark=x,
      boxplot/draw direction=y,
      boxplot/whisker extend=0,
      boxplot/draw/median/.code={%
        \draw[mark size=2pt,/pgfplots/boxplot/every median/.try]
          \pgfextra
          \pgftransformshift{
            \pgfplotsboxplotpointabbox
              {\pgfplotsboxplotvalue{median}}
              {0.5}
          }
          \pgfsetfillcolor{white}
          \pgfuseplotmark{*}
          \endpgfextra
        ;
      },
      boxplot/draw/box/.code={
        \draw[fill,/pgfplots/boxplot/every box/.try]
          ($(boxplot box cs:\pgfplotsboxplotvalue{lower quartile},0.5)!0.5\pgfkeysvalueof{/pgfplots/boxplot/box width}!(boxplot box cs:\pgfplotsboxplotvalue{lower quartile},0)$)
          rectangle
          ($(boxplot box cs:\pgfplotsboxplotvalue{upper quartile},0.5)!0.5\pgfkeysvalueof{/pgfplots/boxplot/box width}!(boxplot box cs:\pgfplotsboxplotvalue{upper quartile},1)$)
        ;
      }
    }
  },
}

\begin{document}

\begin{figure}
  \centering
  \begin{tikzpicture}
    \begin{axis}[
        xtick={1,2,3},
        xticklabels={Group A, Group B, Group C},
        % This somehow fixes everything
        cycle list name={color list},
        solid boxes,
      ]
      \addplot+[% Group A:
        boxplot prepared={
          lower whisker=42, lower quartile=45,
          median=47,
          upper quartile=47.5, upper whisker=48,
        },
      ] table[row sep=\\,y index=0] { 40\\ 34\\ 56\\ };
      \addplot+[% Group B:
        boxplot prepared={
          lower whisker=36, lower quartile=39,
          median=40,
          upper quartile=41, upper whisker=43,
        },
      ] coordinates {};
      \addplot+[% Group C:
        boxplot prepared={
          lower whisker=41, lower quartile=44,
          median=45,
          upper quartile=46, upper whisker=47,
        },
      ] coordinates {(0,35) (0,55)};
    \end{axis}
  \end{tikzpicture}
  \caption[A caption]{A caption for my figure}
\end{figure}

\end{document}

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .