


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