8
$\begingroup$

Is there any way to force DistributionChart to display anything where there is an empty dataset? In the below example I'd like to have 0-s appearing where data is missing, but even a simple Point would be sufficient as that can be labeled.

The problem is that ChartElementFunction is not applied to empty datasets and thus Labeled wrappers are also ignored. Furthermore, ChartLabels (or association keys) cannot be forced to use different sub-labels for successive sets (it's always s1, s2, s3). I'd rather avoid reconstructing coordinates to use with Epilog (I've tried and failed with more complex BarSpacing values) or extract tick coordinates from InputForm[plot] or reconstruct built-in ChartElementFunctions (see ChartElementData@DistributionChart), as these methods are not very robust.

data = <|
   "D1" -> <|"s1" -> {1, 2, 3, 4}, "s2" -> Labeled[{}, "Empty", Center],
             "s3" -> {3, 4, 5, 6}|>,
   "D2" -> <|"s1" -> {}, "s2" -> {}, "s3" -> {}|>,
   "D3" -> <|"s1" -> {3, 4}, "s2" -> {1, 2, 3, 4, 5, 6}, "s3" -> {}|>,
   "D4" -> <|"s1" -> {1, 2}, "s2" -> {3, 4}, "s3" -> {5, 6}|>
   |>;

plot = DistributionChart[Map[Labeled[#, Length@#, Below] &, data, {2}],
 BarSpacing -> {.2, 1}, ChartLabels -> Automatic,
 ChartElementFunction -> "Density"
]

Mathematica graphics

$\endgroup$
  • $\begingroup$ Does replacing {} with {0,0} (i.e.,data2=data /. {}->{0,0}) work? $\endgroup$ – kglr Apr 28 '15 at 17:07
  • $\begingroup$ I think DistributionChart need to have a non empty list to set the lower and upper boundary of the chart. As kguler mentioned, you can also try data2=data /. {}->{n,n}) with any real n. $\endgroup$ – Algohi Apr 28 '15 at 18:00
  • $\begingroup$ @kguler Sure, I can do that, but it would not be rubust: what if my distribution has the expected value of 0? Than I had to replace {} with something else. $\endgroup$ – István Zachar Apr 28 '15 at 21:19
6
$\begingroup$

Update: a custom ChartElementFunction that can be combined with built-in ChartElementFunctions:

ceF2[cedf_: ChartElementDataFunction["Density"]][vpos_: {0, 0}] := If[#3 == {"empty"}, 
 {PointSize[Large], Point[Mean@Transpose@{#[[1]],vpos}]}, cedf[##]] &

Examples: using a dataset that does not require version 10 functions

SeedRandom[1]
datac = {{RandomVariate[PoissonDistribution[5], 30], 
    Labeled[{}, "Empty", Center], 
    RandomVariate[NormalDistribution[], 50]}, {{}, {}, {0, 
     0}}, {RandomVariate[PoissonDistribution[3], 50], 
    RandomChoice[{1, 2, 3, 4, 5, 6}, 100], {}}, {{1, 2}, {3, 4}, {5, 6}}};


vp0 = Min[datac /. Labeled | Style -> (#1 &)];
DistributionChart[Map[Labeled[# /. {} | Labeled[{}, __] :>
    ((vp = {vp0 - 1, vp0 - 1}) -> "empty"), 
    Length[# /. Labeled -> (# &)], Below] &, datac, {2}], 
 BaseStyle -> EdgeForm[], BarSpacing -> {.2, 1}, 
 ChartLabels -> {"s1", "s2", "s3"}, ChartStyle -> 63, 
 ChartElementFunction -> ceF2[][vp], ImageSize -> 600]

Mathematica graphics

Use

ChartElementFunction -> 
 ceF2[ChartElementDataFunction["GlassQuantile", "Quantile" -> 10, 
    "QuantileShading" -> True]][vp]

to get

Mathematica graphics


Original post:

Your data modified to have both {} and {0,0} elements as well as elements with zero mean:

datab= <|"D1" -> <|"s1" -> {1, 2, 3, 4}, "s2" -> Labeled[{}, "Empty", Center],
             "s3" -> {-3,-2,2,3}|>,
   "D2" -> <|"s1" -> {}, "s2" -> {}, "s3" -> {0,0}|>,
   "D3" -> <|"s1" -> {3, 4}, "s2" -> {1, 2, 3, 4, 5, 6}, "s3" -> {}|>,
   "D4" -> <|"s1" -> {1, 2}, "s2" -> {3, 4}, "s3" -> {5, 6}|>
   |>;

Use metadata to distinguish empty sets, and modify the ChartElementFunction to render empty sets as Points:

vp0 = Min[datab /. Labeled|Style->(#&)];
DistributionChart[Map[Labeled[#/.{}|Labeled[{},__]:>
   ((vp={vp0-1,vp0-1})->"empty"), 
   Length[# /.  Labeled ->(#&)], Below] &, datab, {2}],
 BarSpacing -> {.2, 1},ChartLabels ->{"s1", "s2" , "s3" },
ChartElementFunction -> (If[#3 == {"empty"},   
   {PointSize[Large],Point[Mean@Transpose@{#[[1]],vp}]},
   Rectangle @@ Transpose@#1] &)
]

enter image description here

Or define a custom ChartElementDataFunction

ceF[vpos_:{0,0}]:=If[#3 == {"empty"}, PointSize[Large], 
   Point[Mean@Transpose@{#[[1]],vpos}]}, Rectangle@@Transpose@#1] &

and use as

DistributionChart[Map[Labeled[#/.{}|Labeled[{},__]:>
   ((vp={vp0-1,vp0-1})->"empty"), 
   Length[#/.  Labeled[{},__]:>{}], Below] &, datab, {2}],
 BarSpacing -> {.2, 1}, ChartLabels ->{"s1", "s2" , "s3" },
 ChartElementFunction -> ceF[vp]
]

(* same picture *)

$\endgroup$
  • $\begingroup$ Ok, this is even better but it fails when one wants to use built-in chart elements, like "PointDensity", etc. Yes, I forgot to include this in my post (sorry about that), modified now. $\endgroup$ – István Zachar Apr 29 '15 at 15:01
  • $\begingroup$ @Istvan, just added a variant of ceF that takes built-in ChartElementFunctions as input. $\endgroup$ – kglr Apr 29 '15 at 16:13
  • $\begingroup$ Yes, this really pointed me to the right direction, thanks! Previously I failed to figure out how to pass on built-in CEFunctions to my own cef. $\endgroup$ – István Zachar Apr 29 '15 at 19:56
  • $\begingroup$ @Istvan, thanks for the accept. $\endgroup$ – kglr Apr 29 '15 at 20:50
5
$\begingroup$

Would this work for you? I need to assume the data can be transformed into

xData = 
   <|"D1" -> <|"s1" -> {1, 2, 3, 4}, "s2" -> {0, 0}, "s3" -> {3, 4, 5, 6}|>, 
     "D2" -> <|"s1" -> {0, 0}, "s2" -> {0, 0}, "s3" -> {0, 0}|>, 
     "D3" -> <|"s1" -> {3, 4}, "s2" -> {1, 2, 3, 4, 5, 6}, "s3" -> {0, 0}|>, 
     "D4" -> <|"s1" -> {1, 2}, "s2" -> {3, 4}, "s3" -> {5, 6}|>|>

Then the a distribution chart that indicates zero data items where the inner associations have value {0, 0}, can be drawn with

plot = DistributionChart[
  Map[Labeled[#, If[# == {0, 0}, 0, Length @ #], Below] &, xData, {2}],
  BarSpacing -> {.2, 1},
  ChartLabels -> Automatic,
  ChartElementFunction -> ((Rectangle @@ Transpose @ #) &)]

chart

Note: the original data can transformed in the form I use here with

xdata = data /. _Labeled -> {} /. {} -> {0, 0};
$\endgroup$
  • $\begingroup$ +1, really nice trick (I feel ashamed that I have not thought of this). $\endgroup$ – István Zachar Apr 28 '15 at 21:13

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.