MatLab: Create 3D Histogram from sampled data

Richard Laurant picture Richard Laurant · May 28, 2014 · Viewed 7.8k times · Source

I have sampled data in the interval [0,1] in an Array transitions=zeros(101,101) which I want to plot as a 3D-histogram. transitions is filled with data similar to the example data provided at the end of this thread.

The first columns refers to the first observed variable X, the second column to the second variable Y and the third column is the normalized frequency. I.e. for the first row: the observed normalized frequency of the variable pair (0,0) is 0.9459. The sum of the normalized frequencies for (0,Y)thus is 1.

I tried to make (sort of) a 3D histogram with the following code:

        x_c = (transitions(:,1) * 100)+1;
        y = (transitions(:,2) * 100)+1;
        z = transitions(:,4);
        %A = zeros(10,10);
        A = zeros(max(x_c),max(y));
        for i = 1:length(x_c)
            try
                    if(z(i)>0)
                        A(int32(x_c(i)), int32(y(i))) = abs(log(z(i)));
                    else
                        % deal with exceptions regarding log(0)
                        A(int32(x_c(i)), int32(y(i))) = 0;
                    end
            catch
                disp('');
            end
        end
        bar3(A);

However, since it is sampled data in a discrete space A the output looks like the plot below. This is somehow misleading as there are 'gaps' in the plot (z-value = 0 for coordinates where I have no sampled data). I rather would like to have the sampled data being assigned to their corresponding plots, thus resulting in a 'real' 3d histogram.

False histogram

By the way, as a result of my 'hack' of creating A also the x-,y- and z-scale is not correct. The 3D histogram's axes (all three) should be in the interval of [0,1].

ans =

     0         0    0.9459
     0    0.0500    0.0256
     0    0.1000    0.0098
     0    0.1100    0.0004
     0    0.1500    0.0055
     0    0.1600    0.0002
     0    0.2000    0.0034
     0    0.2100    0.0001
     0    0.2500    0.0024
     0    0.2600    0.0001
     0    0.3000    0.0018
     0    0.3200    0.0000
     0    0.3700    0.0000
     0    0.4000    0.0010
     0    0.4200    0.0000
     0    0.4500    0.0007
     0    0.5000    0.0007
     0    0.5300    0.0000
     0    0.5500    0.0005
     0    0.6000    0.0005
     0    0.6300    0.0000
     0    0.7000    0.0002
     0    0.7400         0
     0    0.7500    0.0003
     0    0.7900    0.0000
     0    0.8000    0.0002
     0    0.8400    0.0000
     0    0.8500    0.0002
     0    0.8900    0.0000
     0    0.9000    0.0002
     0    0.9500    0.0001
     0    1.0000    0.0001
0.0500         0    0.0235
0.0500    0.0500    0.0086
0.0500    0.1000    0.0045

     .         .         .
     .         .         .
     .         .         .
     .         .         .
     .         .         .
0.9500    0.9000    0.0035
0.9500    0.9500    0.0066
0.9500    1.0000    0.0180
1.0000         0    0.0001
1.0000    0.0500    0.0001
1.0000    0.1000    0.0001
1.0000    0.1100    0.0000
1.0000    0.1500    0.0001
1.0000    0.1600    0.0000
1.0000    0.2000    0.0001
1.0000    0.2100    0.0000
1.0000    0.2500    0.0001
1.0000    0.2600    0.0000
1.0000    0.3000    0.0001
1.0000    0.3200    0.0000
1.0000    0.3700    0.0000
1.0000    0.4000    0.0002
1.0000    0.4200         0
1.0000    0.4500    0.0002
1.0000    0.5000    0.0003
1.0000    0.5300    0.0000
1.0000    0.5500    0.0004
1.0000    0.6000    0.0004
1.0000    0.6300    0.0000
1.0000    0.7000    0.0007
1.0000    0.7400    0.0000
1.0000    0.7500    0.0010
1.0000    0.7900    0.0000
1.0000    0.8000    0.0015
1.0000    0.8400    0.0001
1.0000    0.8500    0.0024
1.0000    0.8900    0.0002
1.0000    0.9000    0.0042
1.0000    0.9500    0.0111
1.0000    1.0000    0.3998

Answer

Richard Laurant picture Richard Laurant · Jun 2, 2014

I found a solution by working on the non-aggregated data. In particular each row of the data set transitions contains one observation of Xand Y. I used the code below to produce a normalized 3D histogram (and a 2D map) as folllows:

nromalized 3D histogram

function createHistogram(transitions)
   uniqueValues = unique(transitions(:,1));
   biases = cell(numel(uniqueValues),1);

   for i = 1:numel(uniqueValues)
       start = min(find(transitions(:,1) == uniqueValues(i)));
       stop = max(find(transitions(:,1) == uniqueValues(i)));
       biases(i) = mat2cell(transitions(start:stop,2));
   end

   combinedBiases = padcat(biases{1},biases{2},biases{3},biases{4},...
       biases{5},biases{6},biases{7},biases{8},biases{9},biases{10},...
       biases{11},biases{12},biases{13},biases{14},biases{15},biases{16},...
       biases{17},biases{18},biases{19});

   bins = 0:0.1:1;
   [f, x] = hist(combinedBiases, bins);

   %
   % normalize
   %
   for i = 1:numel(f(1,:))
       for j = 1:numel(f(:,i))
            f(j,i) = f(j,i)/numel(biases{i});
       end
   end
   bHandle = bar3(x, f);
   ylim([-0.04,1.04])
   for k = 1:length(bHandle)
        zdata = get(bHandle(k),'ZData');
        set(bHandle(k),'CData',zdata, 'FaceColor','interp');
   end
   colormap('autumn');
   hcol = colorbar();
   axis('square');
   cpos=get(hcol,'Position');
   cpos(4)=cpos(4)/3; % Halve the thickness
   cpos(2)=0.4; % Move it down outside the plot#
   cpos(1)=0.82;
   set(hcol, 'Position',cpos);
   xlabel('Enrollment biases');
   ylabel('Aging biases');
   zlabel('Bias transition probability');
   title(strcat('Probability mass function of bias transitions (', device,')'));
   set(gca,'XTick',0:2:20);
   set(gca,'XTickLabel',0:0.1:1);
   print('-dpng','-r600',strcat('tau_PMF3D_enrollment-ageing-', device));
   view(2);
   cpos(1)=0.84;
   set(hcol, 'Position',cpos);
   print('-dpng','-r600',strcat('tau_PMF2D_enrollment-ageing-', device));
end