function h = swarmchart3(varargin)
%SWARMCHART3 3-d swarm chart.
%   SWARMCHART3(x,y,z) displays a scatter plot in a 3-D view where points 
%   are jittered in the x and y dimensions based on an estimate of the 
%   kernel density in the z dimension for each unique combination of x and 
%   y. 3-D swarm charts provide a visualization for discrete x-y data that 
%   captures the distribution of z data. SWARMCHART3 sets the maximum 
%   jitter width in the x and y dimensions to be 90% of the minimum
%   difference between distinct values in the respective dimensions.
%   
%   SWARMCHART3(x,y,z,sz) draws the markers at the specified sizes (sz)
%   SWARMCHART3(x,y,z,sz,c) uses c to specify color, see SCATTER for a
%   description of how to manipulate color.
%
%   SWARMCHART3(...,M) uses the marker M instead of 'o'.
%   SWARMCHART3(...,'filled') fills the markers
%
%   SWARMCHART3(AX,...) plots into AX instead of GCA.
%   S = SWARMCHART3(...) returns handles to the scatter object created.
%
%   Example:
%       x=randi(4,1000,1);
%       y=randi(4,1000,1);
%       z=randn(1000,1);
%       SWARMCHART3(x,y,z)
%
%   See also SCATTER3, SWARMCHART, BUBBLECHART3.

%   Copyright 2020 The MathWorks, Inc.
narginchk(3,inf)
cax=[];
if isa(varargin{1},'matlab.graphics.Graphics')
    cax=varargin{1};
    varargin(1)=[];
end

x=varargin{1};
y=varargin{2};

if iscategorical(x)
    uniquex=1;
elseif ~isnumeric(x)
    error('MATLAB:scatter3:InvalidSwarm3XData', getString(message('MATLAB:scatter:InvalidSwarmData','X')))
else
    uniquex=unique(x);
end

if iscategorical(y)
    uniquey=1;
elseif ~isnumeric(y)
    error('MATLAB:scatter3:InvalidSwarm3YData', getString(message('MATLAB:scatter:InvalidSwarmData','Y')))
else
    uniquey=unique(y);
end

if numel(uniquex)==1
    jitwidthx=.9;
else
    jitwidthx=.9*min(diff(uniquex));
end

if numel(uniquey)==1
    jitwidthy=.9;
else
    jitwidthy=.9*min(diff(uniquey));
end

try
    if isempty(cax)
        obj = scatter3(varargin{:});
    else
        obj = scatter3(cax,varargin{:});
    end
catch e
    throw(e);
end

if strcmp(obj.XJitterMode,'auto')
    obj.XJitter='density';
end
if strcmp(obj.XJitterWidthMode,'auto')
    obj.XJitterWidth=jitwidthx;
end

if strcmp(obj.YJitterMode,'auto')
    obj.YJitter='density';
end
if strcmp(obj.YJitterWidthMode,'auto')
    obj.YJitterWidth=jitwidthy;
end

if nargout > 0
    h = obj;
end

end