Code covered by the BSD License  

Highlights from
boxplotstack

image thumbnail

boxplotstack

by

 

08 Aug 2011 (Updated )

Displays stacked box plots with labels.

boxplotstack(X,xtick,labels,opacity,bgcolor)
function boxplotstack(X,xtick,labels,opacity,bgcolor)
%BOXPLOTSTACK Displays stacked box plots with labels.
%   boxplotstack(X) displays size(X,2) stacks of box plots, each stack
%   consisting of size(X,1) box plots if X is a cell array, or just one box
%   plot per stack if X is an matrix.
%
%   boxplotstack(X,xtick) sets the x-tick label underneath the n-th stack
%   to xtick{n}.
%
%   boxplotstack(X,xtick,labels) prints the text labels{i,j} next to the
%   box plot corresponding to X{i,j}. If labels{i,j} is a number, it will
%   be printed as a percentage and the opacity values will be taken from
%   labels.
%
%   boxplotstack(X,xtick,labels,opacity) prints the text labels{i,j} next
%   to the box plot corresponding to X{i,j}, with background colour black
%   and opacity equal to opacity{i,j}.
%
%   boxplotstack(X,xtick,labels,opacity,bgcolor) prints the text
%   labels{i,j} next to the box plot corresponding to X{i,j}, with
%   background colour bgcolor{i,j} and opacity equal to opacity{i,j}. The
%   colour should be specified as an RGB triplet [r g b].

%   Version: 2013-05-21
%   Authors: Laurent Sorber (Laurent.Sorber@cs.kuleuven.be)

% Parse input.
if ~iscell(X), X = mat2cell(X,size(X,1),ones(1,size(X,2))); end
if nargin < 2, xtick = {}; end
if nargin < 3, labels = cell(size(X)); end
if nargin < 4, opacity = labels; end
if nargin < 5, bgcolor = cell(size(X)); end

% Compute each box plot's statistics.
stats = cell(size(X));
for j = 1:size(X,2)
    q2 = -inf(size(X,1),1);
    for i = 1:size(X,1)
        
        % Skip this box plot if there is no X associated to it.
        if isempty(X{i,j}), continue; end
        
        % Compute the first, second and third quartiles, and whiskers.
        x = sort(X{i,j});
        n = length(x);
        stat.q2 = median(x);
        stat.q1 = median(x(x<stat.q2));
        stat.q3 = median(x(x>stat.q2));
        stat.w1 = x(find(x >= stat.q1-1.5*(stat.q3-stat.q1),1,'first'));
        stat.w3 = x(find(x <= stat.q3+1.5*(stat.q3-stat.q1),1,'last'));
        stats{i,j} = stat;
        q2(i) = stat.q2;
        
    end
    
    % Sort this column's boxplots in drawing order.
    [tmp,idx] = sort(q2,'descend');
    stats(:,j) = stats(idx,j);
    labels(:,j) = labels(idx,j);
    opacity(:,j) = opacity(idx,j);
    bgcolor(:,j) = bgcolor(idx,j);
    
end

% Draw each box plot.
for j = 1:size(stats,2)
    prevpos = 'r';
    for i = 1:size(stats,1)
        
        % Skip this box plot if there is no X associated to it.
        if isempty(stats{i,j}), continue; end
        
        % Retrieve the previous, current and next statistics.
        statcur = stats{i,j};
        hasprev = i > 1 && ~isempty(stats{i-1,j});
        hasnext = size(stats,1) > 1 && ...
                  i < size(stats,1) && ...
                  ~isempty(stats{i+1,j});
        if hasprev, statprev = stats{i-1,j}; end
        if hasnext, statnext = stats{i+1,j}; end
        
        % Determine the offset of this box plot, to prevent overlap.
        pos = 'c';
        if hasnext && statnext.w3 >= statcur.w1 || ...
           hasprev && statprev.w1 <= statcur.w3
            if strcmp(prevpos,'l'), pos = 'r'; else pos = 'l'; end
        end
        
        % Draw the box plot.
        drawboxplot(statcur,labels{i,j},opacity{i,j},bgcolor{i,j},j,pos);
        prevpos = pos;
        
    end
end

% Set up the axes.
xlim([0.5 size(X,2)+.5]);
set(gca,'XTick',1:size(X,2),'YGrid','on');
if ~isempty(xtick), set(gca,'XTickLabel',xtick); end
hold off;

end

function drawboxplot(stat,label,opac,bgclr,x,pos)

% Define parameters.
obox = 0.13; % The offset of the box if the position is 'l' or 'r'.
wbox = 0.22; % The box width.
wwsk = 0.11; % The whisker width.
mtxt = 0.05; % The margin between the labels and boxes.
ptxt = 1;    % The backgroundcolor margin of the labels in pixels.
if isempty(bgclr)
    ctxt = [0 0 0]; % The fade-to label background colour (fade-from is w).
else
    ctxt = bgclr;
end

% Get box statistics.
q1 = stat.q1;
q2 = stat.q2;
q3 = stat.q3;
w1 = stat.w1;
w3 = stat.w3;

% Draw box.
switch pos
    case 'l', x = x-obox;
    case 'r', x = x+obox;
end
plot([x;x],[q3 w3],'--k'); hold on;
plot([x-wwsk/2;x+wwsk/2],[w3;w3],'k');
plot([x;x],[w1 q1],'--k');
plot([x-wwsk/2;x+wwsk/2],[w1;w1],'k');
plot([x-wbox/2;x-wbox/2;x+wbox/2;x+wbox/2;x-wbox/2],[q1;q3;q3;q1;q1],'b');
plot([x-wbox/2;x+wbox/2],[q2;q2],'r');

% Draw labels.
style = {'Margin',ptxt};
switch pos
    case 'l',
        x = x-wbox/2-mtxt;
        style(end+1:end+2) = {'HorizontalAlignment','right'};
    case {'r','c'}
        x = x+wbox/2+mtxt;
end
if isnumeric(label) && ~isempty(label)
    label = sprintf('%i%%',round(label*100));
end
if isnumeric(opac) && ~isempty(opac)
    style(end+1:end+2) = {'BackgroundColor', ...
                          min(1,(1-opac)*[1 1 1]+opac*ctxt)};
    %if round(100*opac) > 50, style(end+1:end+2) = {'Color','w'}; end
end
if ~isempty(label)
    text(x,q2,label,style{:});
end

end

Contact us