MATLAB Answers

boxchart - many questions! Assign BoxFaceColors? separation lines? numeric xGroupData? Location of boxes? number of points?

169 views (last 30 days)
arnold
arnold on 20 Dec 2020
Edited: Adam Danz on 14 Jan 2021
HI,
with r2020 there is finally a grouped boxplot called "boxchart". However. I don't seem to get the structure and options of it. Multiple questions.
How does one apply any property simultaneously to all boxes instead of looping? For instance like b.Notch = 'on' or a colormap to the ColorGroup? The standard colors especially their order is not what I'm looking for. however, assigning a colormap doesn't work, nor can I apply a b=boxchart()... b.BoxFaceColor = parula(size(b,1)) with n-colors for n-Groups. What am I not seeing here? All I can do is loop over all.
cols = parula(size(b,1));
for i = 1:size(b,1)
bb(i).BoxFaceColor = cols(i,:);
end
% this seems extremely cumbersome
here I have looped over each bb(i) as shown above in order to apply a colr map of my choice. .
Another question that pops up: How could I add separation lines? In the example image above I have added them with an image editor.. obviously not the choice!
Next: Why can't I seem to get a correct looking diagram when plotting when input xGroupData are unique numbers of discrete groups.. The diagram's x-axis or x-grouping is then entirely messed up.
xgroupdata = repmat([0, 0.0125, 0.0250, 0.0375], [1,100]);
ydata = rand(size(xgroupdata));
group = datasample(1:1:5,size(xgroupdata,2));
figure;
boxchart(xgroupdata,ydata, 'GroupByColor', group);
legend;
here is what that code produces. Only Group3 seems to be correctly placed at the proper xgroup-values. But the automatic box-width, doesn't work and the group spacing is also totally messed up, seems to be 0.2 but I can't even find a property in boxchart's documentation
I would like to be able to add a textlabel to any of the boxes with the sample size. For this I need to a) figure out the position of the boxes but I don't manage to understand the structure of the handle... there are zero Children for instance...

Accepted Answer

Adam Danz
Adam Danz on 21 Dec 2020
Edited: Adam Danz on 5 Jan 2021
boxchart vs boxplot
>with r2020 there is finally a grouped boxplot called "boxchart".
The boxplot() function also has grouping options, has been around for much longer, and is often easier to customize than the newer standalone visualzation boxchart function.
ColorGroup & Notches
>How does one apply any property simultaneously to all boxes instead of looping? For instance like b.Notch = 'on' or a colormap to the ColorGroup?
See examples in the boxplot documentation for notches, and a description of ColorGroup.
If you want to use boxchart see the documentation regarding notches.
To apply changes to a group of handles to existing graphics objects, follow this example, although the loop you mentioned is also fine and just as fast (faster?),
h = boxchart(___); % h is a vector of handles
set(h, {'BoxFaceColor'}, mat2cell(jet(numel(h)),ones(numel(h),1),3)) % jet is a colormap
Matlab documentation has a demo showing how to change colors in single bars or groups.
Separation lines
>How could I add separation lines?
For boxplot, use the FactorSeparator option.
For boxchart, this option currently doesn't exist (r2020b). If the x-axis is numeric, add divider lines using,
h = boxchart(__);
xline(x) % where x is the location of the line
If the x-axis is categorical it's a lot more complicated because divider lines cannot be added between categories. To add divider lines on a categorical x-axis you have to add additional categories to the x axis ticks, set their order, and then use xline() (or plot() or line()) with categorical x-values.
% Create boxchart showing 12 months of data
monthNum = randi(12,200,1);
data = rand(200,1)*100.*(normpdf(monthNum,6,1)+.25);
monthAbrv = categorical(monthNum,1:12,month(datetime(1, 1:12, 1), 's'));
figure()
h = boxchart(monthAbrv, data);
% Separate seasons by divider lines
% First add categories to the x-axis
ax = h.Parent; % axis handle
ax.XAxis.Categories' % view current categories.
ans = 1x12 cell array
{'Jan'} {'Feb'} {'Mar'} {'Apr'} {'May'} {'Jun'} {'Jul'} {'Aug'} {'Sep'} {'Oct'} {'Nov'} {'Dec'}
ax.XAxis.Categories = {
'Jan' 'Feb' 'Spring',...
'Mar' 'Apr' 'May' 'Summer',...
'Jun' 'Jul' 'Aug' 'Fall',...
'Sep' 'Oct' 'Nov' 'Winter',...
'Dec'};
% Add xlines on seasonal categories
arrayfun(@(x)xline(x,'r-','LineWidth',1.5),categorical({'Spring','Summer','Fall','Winter'}))
% xline(__) for single lines
% if you want to label each line,
% arrayfun(@(x)xline(x,'r-',x,'LineWidth',1.5),categorical({'Spring','Summer','Fall','Winter'}))
% If needed, removed seasonal tick labels
ax.XTickLabel([3,7,11,15]) = {''};
Fix overlapping boxes in boxchart
>Why can't I seem to get a correct looking diagram when plotting [with grouped data]?
Follow the examples in the documentation for boxchart and look for what's different in your setup.
You can fix the overlapping boxes by making the grouping variable categorical
boxchart(categorical(xgroupdata),ydata, 'GroupByColor', group);
Adding text labels
> I would like to be able to add a textlabel to any of the boxes
Use the text() function. See the bottom of this answer to learn how to get the x value of the boxplot centers.
For numeric axes it's as easy as using the text() function but for categorical axes, you must use categorical coordinates. This demo below shows the number of samples in each category and plots that number above the median lines.
% Produce boxchart
figure()
h = boxchart(randi(5,100,1),rand(100,1));
% compute median and number of samples for each box
[groupID, groups] = findgroups(h.XData);
medians = splitapply(@median,h.YData,groupID);
nSamples = splitapply(@numel,h.YData,groupID);
% Plot text
text(groups, medians, compose('n=%d',nSamples),...
'HorizontalAlignment','Center','VerticalAlignment','bottom', ...
'FontSize',8)
Extracting location of boxs
>I need to a) figure out the position of the boxes but I don't manage to understand the structure of the handle
Extracting the location of the boxes from the graphics handle involves accessing each graphics element and examining its coordinates. It's not easy but achievable with boxplot (see this answer). I haven't figured out a way to achieve this with boxchart as of r2020b.
Of course many of the parameters can be computed using the raw data.
The median marker are easy to get using,
h = boxchart(__);
[groupID, groups] = findgroups(h.XData);
medians = splitapply(@median,h.YData,groupID);
The upper and lower edges of the boxes are the 25th and 75th quartiles,
h = boxchart(__);
[groupID, groups] = findgroups(h.XData);
bounds = splitapply(@(y)quantile(y,[.25,.75]),h.YData,groupID);
The whisker ends are a bit more difficult. They mark the max/min values that are not outliers so first you have to compute the outlier thresholds. Outliers are any values that are greater than 1.5*IQR from the medians. IQR is computed for each box below. See documentation for more info.
h = boxchart(__);
[groupID, groups] = findgroups(h.XData);
IQR = splitapply(@iqr,h.YData,groupID);
The box centers and Left/Right edges for numeric axes are calculated using
h = boxchart(__);
boxCenters = unique(h.XData);
boxEdges = boxCenters(:) + h.BoxWidth.*[-1,1]; % for numeric matrices only
  4 Comments

Sign in to comment.

More Answers (0)

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by