Bin matrix data with nested for loops to create histogram of any size bins

4 views (last 30 days)
Hello!
I am fairly new to programming and could use some help. I have a matrix that contains x & y values for an associated voltage (negative potential values to be specific).
Let's consider just X values for simplicity. What I'd like to do is calculate the average x value, calculate the deviation of x relative to this mean and then plot the x scatter relative to the potential. This gives me a lot of overlappping data points so I want to bin the data (want to be able to vary bin size on the fly). I am having trouble getting my nested for loops which count up data points per bin to output the correct matrix. Basically they are just giving me the negative x and p values out and missing all positive x values. I can't wrap my head around what's incorrect. I'd appreciate any suggestions you might have.
Here's part of my code:
%Calculates the values for x & y relative to their means
xcorr=x-x_avg;
ycorr=y_avg-y;
%Spacer is the predefined bin size in pixels
%p is the vector of potential values (all are negative)
xbins=(ceil(max(xcorr))-floor(min(xcorr)))/spacer;
ybins=(ceil(max(ycorr))-floor(min(ycorr)))/spacer;
pbins=(ceil(abs(max(p)))-floor(min(p)))/spacer;
xstart=floor(min(xcorr));
ystart=floor(min(ycorr));
pstart=ceil(max(p));
for kk=1:pbins
for ii=1:xbins
rowsx=find(xcorr>=xstart+spacer*(ii-1) & xcorr<xstart+spacer*ii & p<=pstart-spacer*(kk-1) & p>pstart-spacer*kk);
numfitx(kk,ii)=length(rowsx);
clear rowsx
end
end
%pixsize is the camera pixel size
xnm_centroid=xstart:spacer:xstart+xbins*spacer;
xnm_centroid=xnm_centroid*pixsize;
%Create histogram figure
figure
iptsetpref('ImshowAxesVisible','on')
imshow(fliplr(numfitx),[],'Xdata',pot_axis,'YData',xnm_centroid)
set(gca,'XDir', 'reverse')
  2 Comments
Guillaume
Guillaume on 20 Jan 2015
I'm really unclear on what you're doing in your loop. You seem to be finding the indices of some values that satisfy a particular criteria and then just recording how many of these indices there are. What is the purpose of that?
Can you explain more clearly what you're doing? Maybe give an example of input data and the expected result.
Most likely, the loops are not necessary.
Are you aware of histc and in R2014b, histcounts?
Maggie Weber
Maggie Weber on 20 Jan 2015
Edited: Maggie Weber on 21 Jan 2015
I have looked over histc, histcn, and a couple other binning programs that people have uploaded. It was my understanding that most of those were for 1D vectors or if they were for 2D data, there were restrictions on the bin size/numbers that made them not useful. If I missed something, I'm happy to take a second look!
I've uploaded a couple of data images to hopefully give you a better idea of what I want. Here is the scatter plot I'd like to bin:
I'd like to bin it to look something like this shown below, except where the x-axis is potential.
My goal with the nested for loops was to use spacer to incrementally step through each of my bins and count up the number of points (from the scatter plot) that occur in each bins. I'd then put this number into a matrix(ii,jj) where ii and jj represent the bin position. Finally, I'd plot the matrix(ii,jj) using imshow.
I can get out matrix(ii,jj) with the code as written but for some reason it's only giving me negative values for X-position (as shown in the scatter plot). I should have both positive and negative X-values.
I realize the nested for loops are very inefficient so if there's a better way to do this without them completely, I'm for it!
Let me know if I need to clarify further! I really appreciate the help.

Sign in to comment.

Accepted Answer

Guillaume
Guillaume on 21 Jan 2015
I'm still unclear on some points. Your plots switch axes from {x, P} to {x, y} so I'm not sure of their relationship. Furthermore you say there are only negative values for x, whereas I can clearly see values for positive x on your plot.
With regards to the histogram, if I understood correctly, this should work:
x = randn(1, 20000), y = randn(1, 20000); %demo data, 20000 points
spacer = 0.05; %demo data
xbins = floor(min(x)):spacer:ceil(max(x));
ybins = floor(min(y)):spacer:ceil(max(y));
%find where points end up on the x/y axis
[~, ~, idx] = histcounts(x, xbins);
[~, ~, idy] = histcounts(y, ybins);
%switch from 2d to 1d, so histogram of 2d data can be computed:
ii = sub2ind(max([idx' idy']), idx, idy); %convert to linear indices
pdf = histc(ii, 1:max(idx)*max(idy)); %histogram of linear indices
%switch back to 2d:
pdf = reshape(pdf, max(idx), max(idy));
imshow(pdf, [], 'XData', xbins, 'YData', ybins);
  2 Comments
Maggie Weber
Maggie Weber on 21 Jan 2015
Sorry that wasn't clear! What I mean is I want to bin the scatter plot data to look similar to the histogram plot below it except with x position (as the y axis) and potential (as the x axis).
The code as I had written it was only outputting a binned histogram with negative values (somehow my code wasn't taking into account the positive values shown in the scatter plot).
Anyway, this looks great. I'll have to do some slight changes to account for my older version of Matlab, but think I can figure that out. Thank you again for taking the time to help me out!
Guillaume
Guillaume on 21 Jan 2015
For older matlab, the only modifications needed are the calls to histcounts. It behaves the same as histc except for the last bin and the order of the return value. if xbins(end) is greater than any value in your x then they behave identically.
Thus:
if ~all(x<xbins(end))
xbins(end) = xbins(end) + 0.001; %or any value, so that the last bin includes values equal to xbins(end)
end
[~, idx] = histc(x, xbins);

Sign in to comment.

More Answers (1)

Image Analyst
Image Analyst on 21 Jan 2015
You can do a histogram of a 2D array with no problem. Just specify your bin edges, then do
counts = histc(array2D(:), edges);

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!