194 lines
7.3 KiB
Matlab
194 lines
7.3 KiB
Matlab
function violins = violinplot(data, cats, varargin)
|
|
%Violinplots plots violin plots of some data and categories
|
|
% VIOLINPLOT(DATA) plots a violin of a double vector DATA
|
|
%
|
|
% VIOLINPLOT(DATAMATRIX) plots violins for each column in
|
|
% DATAMATRIX.
|
|
%
|
|
% VIOLINPLOT(DATAMATRIX, CATEGORYNAMES) plots violins for each
|
|
% column in DATAMATRIX and labels them according to the names in the
|
|
% cell-of-strings CATEGORYNAMES.
|
|
%
|
|
% In the cases above DATA and DATAMATRIX can be a vector or a matrix,
|
|
% respectively, either as is or wrapped in a cell.
|
|
% To produce violins which have one distribution on one half and another
|
|
% one on the other half, DATA and DATAMATRIX have to be cell arrays
|
|
% with two elements, each containing a vector or a matrix. The number of
|
|
% columns of the two data sets has to be the same.
|
|
%
|
|
% VIOLINPLOT(DATA, CATEGORIES) where double vector DATA and vector
|
|
% CATEGORIES are of equal length; plots violins for each category in
|
|
% DATA.
|
|
%
|
|
% VIOLINPLOT(TABLE), VIOLINPLOT(STRUCT), VIOLINPLOT(DATASET)
|
|
% plots violins for each column in TABLE, each field in STRUCT, and
|
|
% each variable in DATASET. The violins are labeled according to
|
|
% the table/dataset variable name or the struct field name.
|
|
%
|
|
% violins = VIOLINPLOT(...) returns an object array of
|
|
% <a href="matlab:help('Violin')">Violin</a> objects.
|
|
%
|
|
% VIOLINPLOT(..., 'PARAM1', val1, 'PARAM2', val2, ...)
|
|
% specifies optional name/value pairs for all violins:
|
|
% 'Width' Width of the violin in axis space.
|
|
% Defaults to 0.3
|
|
% 'Bandwidth' Bandwidth of the kernel density estimate.
|
|
% Should be between 10% and 40% of the data range.
|
|
% 'ViolinColor' Fill color of the violin area and data points. Accepts
|
|
% 1x3 color vector or nx3 color vector where n = num
|
|
% groups. In case of two data sets being compared it can
|
|
% be an array of up to two cells containing nx3
|
|
% matrices.
|
|
% Defaults to the next default color cycle.
|
|
% 'ViolinAlpha' Transparency of the violin area and data points.
|
|
% Can be either a single scalar value or an array of
|
|
% up to two cells containing scalar values.
|
|
% Defaults to 0.3.
|
|
% 'MarkerSize' Size of the data points, if shown.
|
|
% Defaults to 24
|
|
% 'MedianMarkerSize' Size of the median indicator, if shown.
|
|
% Defaults to 36
|
|
% 'EdgeColor' Color of the violin area outline.
|
|
% Defaults to [0.5 0.5 0.5]
|
|
% 'BoxColor' Color of the box, whiskers, and the outlines of
|
|
% the median point and the notch indicators.
|
|
% Defaults to [0.5 0.5 0.5]
|
|
% 'MedianColor' Fill color of the median and notch indicators.
|
|
% Defaults to [1 1 1]
|
|
% 'ShowData' Whether to show data points.
|
|
% Defaults to true
|
|
% 'ShowNotches' Whether to show notch indicators.
|
|
% Defaults to false
|
|
% 'ShowMean' Whether to show mean indicator
|
|
% Defaults to false
|
|
% 'ShowBox' Whether to show the box.
|
|
% Defaults to true
|
|
% 'ShowMedian' Whether to show the median indicator.
|
|
% Defaults to true
|
|
% 'ShowWhiskers' Whether to show the whiskers
|
|
% Defaults to true
|
|
% 'GroupOrder' Cell of category names in order to be plotted.
|
|
% Defaults to alphabetical ordering
|
|
|
|
% Copyright (c) 2016, Bastian Bechtold
|
|
% This code is released under the terms of the BSD 3-clause license
|
|
|
|
hascategories = exist('cats','var') && not(isempty(cats));
|
|
|
|
%parse the optional grouporder argument
|
|
%if it exists parse the categories order
|
|
% but also delete it from the arguments passed to Violin
|
|
grouporder = {};
|
|
idx=find(strcmp(varargin, 'GroupOrder'));
|
|
if ~isempty(idx) && numel(varargin)>idx
|
|
if iscell(varargin{idx+1})
|
|
grouporder = varargin{idx+1};
|
|
varargin(idx:idx+1)=[];
|
|
else
|
|
error('Second argument of ''GroupOrder'' optional arg must be a cell of category names')
|
|
end
|
|
end
|
|
|
|
% check and correct the structure of ViolinColor input
|
|
idx=find(strcmp(varargin, 'ViolinColor'));
|
|
if ~isempty(idx) && iscell(varargin{idx+1})
|
|
if length(varargin{idx+1}(:))>2
|
|
error('ViolinColor input can be at most a two element cell array');
|
|
end
|
|
elseif ~isempty(idx) && isnumeric(varargin{idx+1})
|
|
varargin{idx+1} = varargin(idx+1);
|
|
end
|
|
|
|
% check and correct the structure of ViolinAlpha input
|
|
idx=find(strcmp(varargin, 'ViolinAlpha'));
|
|
if ~isempty(idx) && iscell(varargin{idx+1})
|
|
if length(varargin{idx+1}(:))>2
|
|
error('ViolinAlpha input can be at most a two element cell array');
|
|
end
|
|
elseif ~isempty(idx) && isnumeric(varargin{idx+1})
|
|
varargin{idx+1} = varargin(idx+1);
|
|
end
|
|
|
|
% tabular data
|
|
if isa(data, 'dataset') || isstruct(data) || istable(data)
|
|
if isa(data, 'dataset')
|
|
colnames = data.Properties.VarNames;
|
|
elseif istable(data)
|
|
colnames = data.Properties.VariableNames;
|
|
elseif isstruct(data)
|
|
colnames = fieldnames(data);
|
|
end
|
|
catnames = {};
|
|
if isempty(grouporder)
|
|
for n=1:length(colnames)
|
|
if isnumeric(data.(colnames{n}))
|
|
catnames = [catnames colnames{n}]; %#ok<*AGROW>
|
|
end
|
|
end
|
|
catnames = sort(catnames);
|
|
else
|
|
for n=1:length(grouporder)
|
|
if isnumeric(data.(grouporder{n}))
|
|
catnames = [catnames grouporder{n}];
|
|
end
|
|
end
|
|
end
|
|
|
|
for n=1:length(catnames)
|
|
thisData = data.(catnames{n});
|
|
violins(n) = Violin({thisData}, n, varargin{:});
|
|
end
|
|
set(gca, 'XTick', 1:length(catnames), 'XTickLabels', catnames);
|
|
set(gca,'Box','on');
|
|
return
|
|
elseif iscell(data) && length(data(:))==2 % cell input
|
|
if not(size(data{1},2)==size(data{2},2))
|
|
error('The two input data matrices have to have the same number of columns');
|
|
end
|
|
elseif iscell(data) && length(data(:))>2 % cell input
|
|
error('Up to two datasets can be compared');
|
|
elseif isnumeric(data) % numeric input
|
|
% 1D data, one category for each data point
|
|
if hascategories && numel(data) == numel(cats)
|
|
if isempty(grouporder)
|
|
cats = categorical(cats);
|
|
else
|
|
cats = categorical(cats, grouporder);
|
|
end
|
|
|
|
catnames = (unique(cats)); % this ignores categories without any data
|
|
catnames_labels = {};
|
|
for n = 1:length(catnames)
|
|
thisCat = catnames(n);
|
|
catnames_labels{n} = char(thisCat);
|
|
thisData = data(cats == thisCat);
|
|
violins(n) = Violin({thisData}, n, varargin{:});
|
|
end
|
|
set(gca, 'XTick', 1:length(catnames), 'XTickLabels', catnames_labels);
|
|
set(gca,'Box','on');
|
|
return
|
|
else
|
|
data = {data};
|
|
end
|
|
end
|
|
|
|
% 1D data, no categories
|
|
if not(hascategories) && isvector(data{1})
|
|
violins = Violin(data, 1, varargin{:});
|
|
set(gca, 'XTick', 1);
|
|
% 2D data with or without categories
|
|
elseif ismatrix(data{1})
|
|
for n=1:size(data{1}, 2)
|
|
thisData = cellfun(@(x)x(:,n),data,'UniformOutput',false);
|
|
violins(n) = Violin(thisData, n, varargin{:});
|
|
end
|
|
set(gca, 'XTick', 1:size(data{1}, 2));
|
|
if hascategories && length(cats) == size(data{1}, 2)
|
|
set(gca, 'XTickLabels', cats);
|
|
end
|
|
end
|
|
|
|
set(gca,'Box','on');
|
|
|
|
end
|