gusucode.com > datatypes 工具箱matlab源码程序 > datatypes/@categorical/pie.m

    function h = pie(varargin)
%PIE Pie chart of a categorical array
%   PIE(X) draws a pie chart for categorical array X with category counts 
%   normalized to total number of elements. <undefined> elements are ignored.
%
%   PIE(X,EXPLODE) is used to specify slices that should be pulled out from
%   the pie.  EXPLODE can be category names or a logical vector with the
%   same number of elements as categories in X. When EXPLODE is category 
%   names, slices corresponding to categories specified will be pulled out. 
%   When EXPLODE is a logical vector, slices corresponding to TRUE in 
%   category order will be pulled out.
%
%   PIE(X,EXPLODE,LABELS) is used to label each pie slice with LABELS.
%   LABELS must be a character vector or cell array of character vectors.
%   If LABELS is a cell array, it must have the same number of elements as
%   categories in X.
%
%   PIE(AX,...) plots into AX instead of GCA.
%
%   H = PIE(...) returns a vector containing patch and text handles.
%
%   Example
%   --------
%   Plot a pie chart from a categorical array
%      X = categorical({'North','South','North','East','South','West'});
%      pie(X);
%
%   Explode slices corresponding to categories 'North' and 'South'
%      pie(X, {'North','South'});
%
%   Explode categories 'North' and 'South' using logical vector
%      pie(X, [false true true false]);
%
% Copyright 2014-2016 The MathWorks, Inc.

% Parse and process inputs
[axesHandle, data, explode, labels] = pieProcessInputs(varargin);

% Compute category counts and ignore categories with zero counts
counts = countcats(data);
categoryNames = categories(data);
if any(counts==0) % some category has zero counts
    nnzCountsInd = find(counts); % categories with zero counts are ignored
    
    counts = counts(nnzCountsInd);
    explode = explode(nnzCountsInd);
    categoryNames = categoryNames(nnzCountsInd);
    if ~isempty(labels)
        labels = labels(nnzCountsInd);
    end
end

% Plot pie chart and label slices appropriately
lh = pie(axesHandle, counts, explode);
legend(categoryNames); legend('off');

pieInsertLabels(lh, labels, categoryNames, counts);
if nargout>0, h=lh; end

end


%%%%%%%%%%%%%%%%%%%%%%%%% HELPER PIEPROCESSINPUTS %%%%%%%%%%%%%%%%%%%%%%%%%
function [axesHandle, catData, explode, labels] = pieProcessInputs(arg)
% Get axes handle for this plot
if ishghandle(arg{1},'axes')
    axesHandle = arg{1}; % get user specified axes handle
    arg(1)=[]; % delete 1st argument so subsequent input parsing doesn't need to special case
else
    axesHandle = [];
end

try
    catData = arg{1};
    numParameters = numel(arg);
    switch numParameters
        case 1
            explode = {};
            labels = {};
        case 2
            explode = arg{2};
            labels = {};
        case 3
            explode = arg{2};
            labels = arg{3};
        otherwise
            error(message('MATLAB:categorical:pie:TooManyInputs'));
    end
    
    catData = validateData(catData);
    explode = validateExplode(explode, catData);
    labels = validateLabels(labels, numel(categories(catData)));
    
catch ME
    throwAsCaller(ME);
end

% Create new axes if user did not specify
if isempty(axesHandle), axesHandle = gca; end
end
%%%%%%%%%%%%%%%%%%%%%%%%%%% HELPER VALIDATEDATA %%%%%%%%%%%%%%%%%%%%%%%%%%%
function data = validateData(data)
data = reshape(data,numel(data),1);
if isempty(data) || all(isundefined(data))
    error(message('MATLAB:categorical:pie:InvalidData'));
end
end
%%%%%%%%%%%%%%%%%%%%%%%%% HELPER VALIDATEEXPLODE %%%%%%%%%%%%%%%%%%%%%%%%%%
function explode = validateExplode(explode, catData)
if isempty(explode)
    explode = false(size( countcats(catData) ));
elseif islogical(explode) || (isnumeric(explode) && all(~isnan(explode)))
    if ~isequal( numel(explode), numel(categories(catData)) ) % length of EXPLODE must equal that of the categorical array
        error(message('MATLAB:categorical:pie:InvalidExplodeLogical'));
    end
    explode = logical(explode);
elseif matlab.internal.datatypes.isCharStrings(explode)
    if ~all(iscategory(catData,explode)) % explode specified as category names
        error(message('MATLAB:categorical:pie:InvalidExplodeName'));
    end
    explode = ismember(categories(catData), explode);
else
    error(message('MATLAB:categorical:pie:InvalidExplodeType'));
end
end
%%%%%%%%%%%%%%%%%%%%%%%%%% HELPER VALIDATELABELS %%%%%%%%%%%%%%%%%%%%%%%%%%
function labels = validateLabels(labels, numCat)
if ~matlab.internal.datatypes.isCharStrings(labels,true)
    error(message('MATLAB:categorical:pie:InvalidLabel'));
elseif ~isempty(labels) && ~isequal(numel(labels), numCat) % LABELS must be empty or have number of elements as that of categories
    error(message('MATLAB:categorical:pie:InvalidLabel'));
end
end
%%%%%%%%%%%%%%%%%%%%%%%%% HELPER PIEINSERTLABELS %%%%%%%%%%%%%%%%%%%%%%%%%%
function labels = pieInsertLabels(h, labels, catNames, catCounts)
if isempty(labels)
    percentageStrings = num2str(round(100*nonzeros(catCounts)./sum(catCounts)), '(%d%%)');
    labels = strcat(catNames, {' '}, percentageStrings);
end

% Save 'Extent' property of default labels for positioning of custom labels
hText = findobj(h,'Type','text');
oldExtents = get(hText,'Extent');
if iscell(oldExtents), oldExtents = cell2mat(oldExtents); end

% Set labels to categories and corresponding percentages
labels = reshape(labels, size(hText));
set(hText,{'String'},labels);

% Compute position of custom labels so they do not overlap with the slices
newExtents = get(hText,'Extent');
if iscell(newExtents), newExtents = cell2mat(newExtents); end
width_change = newExtents(:,3)-oldExtents(:,3);
offset = sign(oldExtents(:,1)) .* (width_change/2);
textPositions = get(hText,{'Position'});
if iscell(textPositions), textPositions  = cell2mat(textPositions); end
textPositions(:,1) = textPositions(:,1) + offset; % add offset adjustment

% Set 'Position' property for each custom label
for i=1:numel(hText)
    set(hText(i),'Position',textPositions(i,:))
end
end