


HISTXYZ 3-Dimensional Density Histogram.
HISTXYZ(DATA_MTX), where DATA_MTX is an (M x 3) matrix, visualizes
the density of a 3-D scatter plot. The rows generate a 3-D histogram
which is then smoothed with a 3-D Gaussian kernel. This histogram is
treated as a scalar-valued volume and isocontours are found at a number
of density levels, each drawn as a transparent, colored surface. The
coloring of the axes labels is (R,G,B) <=> (X,Y,Z).
Note that the fine details of the volume are simplified for graphics
efficiency beyond simple smoothing and will not necessarily be
accurate in details.
When called as [N,X,Y,Z] = HISTXYZ(...), the function returns the 3-D
histogram and associated indices rather than drawing the volume.
The surface is controlled by 4 optional arguments:
HISTXYZ(DATA_MTX, BINS, SMOOTHSD, LEVELS, COLOR, NEWFIG)
Any optional argument specified as [] will use its default value.
The definitions of the control arguments and there defaults are:
BINS (default: 50) Number of bins used to discretize
the data.
SMOOTHSD (default: 1) The standard deviation in bin units
for a Gaussian smoothing kernel.
LEVELS (default: 10) A scalar value is taken as the #
of evenly spaced density levels at which to
draw a contour. Vectors with values between
[0..1] are treated as fractions of max density,
e.g., [0.1 0.2 0.3] shows contours at 10%, 20%
and 30% of max density.
COLOR (default: evenly spaced intervals in the colormap
are used for increasing density contours) If
specified as [R G B], it is taken to represent
a single color at which all contours will be drawn.
NEWFIG (default : 1) Set to 0 to draw on the current axes
without changing camera properties.

0001 function [smoothdata,x_inds,y_inds,z_inds] = ... 0002 histxyz(data_mtx, bins, smoothsd, levels, color, newfig) 0003 %HISTXYZ 3-Dimensional Density Histogram. 0004 % HISTXYZ(DATA_MTX), where DATA_MTX is an (M x 3) matrix, visualizes 0005 % the density of a 3-D scatter plot. The rows generate a 3-D histogram 0006 % which is then smoothed with a 3-D Gaussian kernel. This histogram is 0007 % treated as a scalar-valued volume and isocontours are found at a number 0008 % of density levels, each drawn as a transparent, colored surface. The 0009 % coloring of the axes labels is (R,G,B) <=> (X,Y,Z). 0010 % Note that the fine details of the volume are simplified for graphics 0011 % efficiency beyond simple smoothing and will not necessarily be 0012 % accurate in details. 0013 % 0014 % When called as [N,X,Y,Z] = HISTXYZ(...), the function returns the 3-D 0015 % histogram and associated indices rather than drawing the volume. 0016 % 0017 % The surface is controlled by 4 optional arguments: 0018 % HISTXYZ(DATA_MTX, BINS, SMOOTHSD, LEVELS, COLOR, NEWFIG) 0019 % 0020 % Any optional argument specified as [] will use its default value. 0021 % The definitions of the control arguments and there defaults are: 0022 % BINS (default: 50) Number of bins used to discretize 0023 % the data. 0024 % SMOOTHSD (default: 1) The standard deviation in bin units 0025 % for a Gaussian smoothing kernel. 0026 % LEVELS (default: 10) A scalar value is taken as the # 0027 % of evenly spaced density levels at which to 0028 % draw a contour. Vectors with values between 0029 % [0..1] are treated as fractions of max density, 0030 % e.g., [0.1 0.2 0.3] shows contours at 10%, 20% 0031 % and 30% of max density. 0032 % COLOR (default: evenly spaced intervals in the colormap 0033 % are used for increasing density contours) If 0034 % specified as [R G B], it is taken to represent 0035 % a single color at which all contours will be drawn. 0036 % NEWFIG (default : 1) Set to 0 to draw on the current axes 0037 % without changing camera properties. 0038 0039 % fraction of faces to be retained during patch simplification 0040 patch_reduction = 0.3; 0041 0042 %%%%%%%%%%%%%%%%%%%%%%%%%%%% Parse Inputs %%%%%%%%%%%%%%%%%%%%%%%%%%%% 0043 if (size(data_mtx,2) ~= 3), error('Data must by [m x 3].'); end 0044 if (nargin < 2 || isempty(bins)), bins = 50; end 0045 if (nargin < 3 || isempty(smoothsd)), smoothsd = 1; end 0046 if (nargin < 4 || isempty(levels)), levels = 10; 0047 else 0048 if (numel(levels) == 1) 0049 if (levels < 1), error('If the ''levels argument is a scalar, it must be > 1.'''); end 0050 elseif ((ndims(levels) > 2) || (any(levels > 1) || any(levels < 0))) 0051 error('If the ''levels'' argument is a vector, it must be 2-D and it cannot have any values outside of [0..1].'); 0052 end 0053 end 0054 if (nargin < 5 || isempty(color)), color = colormap; end 0055 if (nargin < 6 || isempty(newfig)), newfig = 1; end 0056 0057 0058 %%%%%%%%%%%%%%%%%%%%%%%%%%%% Rescale Data %%%%%%%%%%%%%%%%%%%%%%%%%%%% 0059 % Scale the data to a range convenient for histogramming . . . 0060 [data1,min1,max1] = rescale(data_mtx(:,1),1,bins); data1 = round(data1); 0061 [data2,min2,max2] = rescale(data_mtx(:,2),1,bins); data2 = round(data2); 0062 [data3,min3,max3] = rescale(data_mtx(:,3),1,bins); data3 = round(data3); 0063 0064 % Construct index vectors from the original ranges of the data. 0065 x_inds = linspace(min1,max1,bins); 0066 y_inds = linspace(min2,max2,bins); 0067 z_inds = linspace(min3,max3,bins); 0068 0069 0070 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Histogram %%%%%%%%%%%%%%%%%%%%%%%%%%%%% 0071 % Construct the 3-D scatter density 0072 % 'sparse' only works in 2-D so we combine the first 2 dimensions ... 0073 counts = full(sparse(data2+(bins)*(data1-1), data3, 1, bins^2, bins)); 0074 counts = reshape(counts,[bins,bins,bins]); % . . . and now separate them. 0075 0076 0077 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Graphics %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 0078 if (nargout > 0), return; end; 0079 % First we smooth: 0080 kernelsize = ceil(smoothsd*8 + 1); 0081 smoothdata = smooth3f(counts, 'gaussian', kernelsize, smoothsd); 0082 0083 % Now determine which contour levels we'll want to draw. 0084 maxdens = max(smoothdata(:)); 0085 onedens = max(max(max(gausskernel(kernelsize*ones(1,3), smoothsd)))); 0086 if (numel(levels) == 1) 0087 showlevels = linspace(onedens,maxdens,levels+1); 0088 showlevels = showlevels(1:end-1); 0089 else 0090 showlevels = round(sort(levels) * maxdens); 0091 end 0092 0093 % Set up evenly spaced colors. 0094 cmap = color; 0095 cind = floor(linspace(1,size(cmap,1),length(showlevels))); 0096 0097 % Prepare figure and prettify. 0098 if (newfig) 0099 figure; 0100 grid on; set(gca,'box','on'); daspect([1,1,1]); view(3); 0101 end 0102 axhand = gca; 0103 0104 % Next we actually draw the contours. 0105 for contour = 1:length(showlevels) 0106 fv = isosurface(x_inds,y_inds,z_inds,smoothdata,showlevels(contour)); 0107 fv = reducepatch(fv, patch_reduction); 0108 p = patch(fv); 0109 0110 set(p, 'FaceColor', cmap(cind(contour),:), 'EdgeColor', 'none'); 0111 % The alpha decreases inversely (to countour #) to emulate increasing density. 0112 set(p, 'AlphaDataMapping', 'none', 'FaceAlpha', 1/(length(showlevels))); 0113 0114 drawnow; 0115 end 0116 0117 % Prepare the axes for rotating and add some lighting 0118 if (newfig) 0119 axis tight; 0120 set(axhand,'CameraViewAngleMode','manual', 'CameraViewAngle', 10); 0121 end 0122 material dull; 0123 lighting gouraud; lightangle(90,60); lightangle(270,10); 0124 0125 % Finally, color the tick marks . . . 0126 set(axhand, 'Xcolor', [0.6 0 0]); 0127 set(axhand, 'Ycolor', [0 0.6 0]); 0128 set(axhand, 'Zcolor', [0 0 0.6]); 0129 0130 % . . . and make sure that nothing is returned. 0131 clear smoothdata x_inds y_inds z_inds