BoxWhiskerPlot - how to specify boxes position on the horizontal axis

Since the BoxWhiskerChart doesn't label its x-axis coordinate, I decided to make use of the functionality that already exists in ErrorListPlot. The latter is part of the "ErrorBarPlots" package which has to be loaded explicitly.

First I generate the data, then I extract a list of coordinates for ErrorListPlot, then I specify a function that renders the "error bar" as a BoxWhiskerChart for each data set individually. The scale has to be common to all plots, and that's achieved with a combination of fixed PlotRange and AspectRatio -> Full for the inset whisker plots.

data = {{1, RandomInteger[{-10, 10}, 10]}, {3, 
    RandomInteger[{-10, 10}, 10]}, {10, RandomInteger[{-10, 10}, 10]}};

data = {{1, {7, -9, 5, 1, 3, 8, 10, 10, -3, 
     0}}, {3, {-8, -6, -6, 7, -8, -8, 2, -8, -2, -4}}, {10, {-9, -3, 
     9, 5, -1, 0, 9, 2, 3, -1}}};

dataValues = data[[All, 2]];

The original chart is here:

BoxWhiskerChart[dataValues]

chart

Now for the modifications to ErrorListPlot:

{min, max} = {Min[#], Max[#]} &@Flatten[dataValues]

(* ==> {-9, 10} *)

kValues = MapIndexed[Flatten[{#, min, #2}] &, data[[All, 1]]];

whiskers = Map[
   BoxWhiskerChart[#, Frame -> None, PlotRange -> {min, max}, 
     AspectRatio -> Full, PlotRangePadding -> 0, 
     PlotRangeClipping -> False] &,
   dataValues];

Needs["ErrorBarPlots`"]

errorfunction[{x_, y_}, err_] := Inset[
  whiskers[[Last[Flatten[List @@ err]]]],
  {x, y}, {Center, Bottom}, Scaled[{.1, 1}]]

ErrorListPlot[kValues, ErrorBarFunction -> errorfunction, 
 PlotMarkers -> "", PlotRange -> {min, max}]

error plot

The tooltips of the original chart still work in this plot, too.

Edit

In response to the additional question about logarithmic x axis, we can work with the same data but can't use ErrorListPlot. So instead one could do this:

ListLogLinearPlot[
   List /@ kValues[[All, 1 ;; 2]], 
   PlotMarkers -> Map[{#, 1} &, whiskers], 
   PlotRange -> {min, max}] /. 
  Inset[i_, pos_, align_, scl_] :> 
   Inset[i, pos, {Center, Bottom}, Scaled[{.1, 1}]]

The idea is the same as above: "inject" the BoxWhiskerChart at the correct location by means of an Inset. The positioning can be taken care of by the plot function, but the scaling is not under my control in the plotting process. So I have to fix that by post-processing using the replacement /. with a rule that looks for Inset in the finished plot and aligns its bottom with the plot point coordinate. The latter is always equal to the minimum data value (min), so that by setting PlotRange and using Scaled[{.1, 1}] for the fourth Inset argument we get the same result as in ErrorListPlot, only with a logarithmic axis:

log axis

This last approach would of course also work with ListPlot and could therefore be a replacement for my my first solution.

A limitation of both approaches is that the vertical PlotRange must correspond exactly to the one in the BoxWhiskerChart, so that the scaling works properly by assuming the Inset should span 100% of the vertical space. This means you can't add PlotRangePadding in the vertical direction. You can add it in the horizontal direction, though. Here is an illustration of an explicit horizontal PlotRange to keep the bars away from the edges:

ListLogLinearPlot[
  List /@ kValues[[All, 1 ;; 2]], 
  PlotMarkers -> Map[{#, 1} &, whiskers],
  AxesOrigin -> {.9, 0},
  PlotRange -> {{.9, 11}, {min, max}}] /. 
 Inset[i_, pos_, align_, scl_] :> 
  Inset[i, pos, {Center, Bottom}, Scaled[{.1, 1}]]

plotrange example


From docs > BoxWhiskerChart >Scope > Data and Wrappers:

Nonreal data is taken to be missing and typically yields a gap in the box-and-whisker chart

So one can use the following approach:

salaries = ExampleData[{"Statistics", "UniversitySalaries"}, "DataElements"];
depts = {"Mathematics", "History", "English", "Chemistry", "Law", "Physics", "Statistics"};
data = Table[Cases[salaries, {d, _, salary_, "A"} :> salary], {d, depts}];
xrange = {1, 2, 5, 7, 10, 11, 12};
newdata = ConstantArray[Missing[], Max[xrange]];
newdata[[xrange]] = data;
xlabels = ConstantArray["", Max[xrange]];
xlabels[[xrange]] = xrange;

BoxWhiskerChart[newdata, ChartLabels -> Placed[xlabels, Axis],
  ChartStyle -> 10, Joined -> True, ImageSize -> 500]

enter image description here


At the request of one user I included a BoxWhisherDraw statement in the latest release of Presentations (which I sell for $50.). This essentially draws a chart centered at zero and then you can easily Scale/Rotate/Translate it to wherever you wish. So here is a solution to your problem using BoxWiskerDraw:

<<Presentations`

data[1] = Array[RandomReal[{0, 1}] &, 10];
data[3] = Array[1 + RandomReal[{0, 3}] &, 10];
data[10] = Array[5 + RandomReal[{0, 10}] &, 10];


xticks = CustomTicks[Identity, databased[{1, 3, 10}]];
Draw2D[
 {({BoxWhiskerDraw[data[#],
         ChartStyle -> 
          Directive[FaceForm[Opacity[0.2, Blue]], EdgeForm[Black], 
           Thin]],
        CirclePoint[{0, #}, 3, Black, White] & /@ data[#]} // 
       ScaleOp[{3, 1}, {0, 0}] // TranslateOp[{#, 0}]) & /@ {1, 3, 
    10}},
 Frame -> True,
 FrameTicks -> {{Automatic, Automatic}, {xticks, 
    xticks // NoTickLabels}},
 PlotLabel -> Style["Custom BoxWhisker Chart", 13, Bold],
 ImageSize -> 300]

Mathematica graphics

I also used CirclePoint to mark the data points for each data set and I used CustomTicks to put ticks at just the k values.

Addition

The poster asked if a log x axis could be used. Yes, very simple. In the above we simply add a Log10 as the scaling function in CustomTicks and to the TranslateOp command. And we change the width scaling in ScaleOp.

xticks = CustomTicks[Log10, databased[{1, 3, 10}]];
Draw2D[
 {({BoxWhiskerDraw[data[#],
         ChartStyle -> 
          Directive[FaceForm[Opacity[0.2, Blue]], EdgeForm[Black], 
           Thin]],
        CirclePoint[{0, #}, 3, Black, White] & /@ data[#]} // 
       ScaleOp[{1/2, 1}, {0, 0}] // 
      TranslateOp[{Log10[#], 0}]) & /@ ({1, 3, 10})},
 AspectRatio -> 1,
 PlotRange -> {{-0.3, 1.3}, {Automatic, Automatic}},
 Frame -> True,
 FrameTicks -> {{Automatic, Automatic}, {xticks, 
    xticks // NoTickLabels}},
 PlotLabel -> Style["Custom BoxWhisker Chart", 13, Bold],
 ImageSize -> 300]

Mathematica graphics