Count strings occurrences and plot histogram - matlab

Is there any straightforward way to create a histogram from a cell array like the one below? The spacing between the consecutive bars should be exactly the same and the labels of the x-axis should be the corresponding names of the variables below in a vertical orientation.
'w464'
'w462'
'w461'
'w464'
'w461'
'w463'
'w466'
'w461'

I would like to know a better way, as well. Fwiw, I have used countmember in a roundabout way to plot data like this. I.E. if the data you posted was named A
>> B={sort(unique(A)) countmember(sort(unique(A)),A)};
>> bar(B{2});
>> set(gca,'XTickLabel',B{1})

If you have access to the statistics toolbox, grp2idx is very useful:
%# sorting is only necessary if the output should be sorted as well
[idx,label] = grp2idx(sort(A))
hist(idx,unique(idx));
set(gca,'xTickLabel',label)

A solution that only uses built-in functions
[u,~,n] = unique(A(:));
B = accumarray(n, 1, [], #sum);
bar(B)
set(gca,'XTickLabel',u)

You can also use the histogram function as follows:
[C,~,ic] = unique(A);
fig1 = figure;
axes1 = axes('Parent',fig1,'XTickLabel',C,'XTick',1:length(C));
hold(axes1,'on');
histogram(ic)

Related

How can I build custom xticklabels using numbers and strings?

I am trying to customize the Xticklabels of my bar graph to have a format of 'number (units)'
So far I have a vector:
scanrate = [2;4;6;8;10];
I want my bar graph to have an x axis of:
2mv/s 4mv/s 6mv/s 8mv/s 10mv/s
If I use xticklabels(num2str(scanrate))
the xticklabels change to the numbers in the scanrate vector. I want to put mv/s after each Xtick.
You can also use strcat :
xticklabels(strcat(num2str(scanrate),' mv/s'))
Please note that it works only when scanrate is a column vector.
Fun fact :
num2str(scanrate) + " mv/s"
also works, but
num2str(scanrate) + ' mv/s'
does not
Build your strings using sprintf(), where the %d flag is for an unsigned integer:
my_labels = {};
for ii = 1:numel(scanrate)
my_labels{ii} = sprintf('%dmv/s', scanrate(ii));
end
figure;
% (...) make your plot
xticklabels(my_labels)
Alternative one-liner, thanks to Wolfie's comment:
my_labels = arrayfun(#(x)sprintf('%dmv/s',x),scanrate,'uni',0);
As a side note: that's normally not what you'd do when creating these type of plots. You'd just have numbers on the axes and a label stating something as "Velocity [mv/s]", rather than having the unit on every single tick label.

Plot means over grouped boxplot in MATLAB?

I am using multiple_boxplot function to generate grouped boxplots:
http://au.mathworks.com/matlabcentral/fileexchange/47233-multiple-boxplot-m
However, instead of medians I want to plot means. First I tried general method:
plot([mean(x)],'dg');
But it did not work. I tried to extract the means and then plot them but that also is not working.
m=[];
for i=1:max(group)
idx=find(group==i);
m=[m nanmean(x(idx))];
end
boxplot(x,group, 'positions', positions);hold on
plot([m],'dg')
What am I doing wrong? And how to plot the means with each boxplot?
Thanks.
You can do the following:
In the function multiple_boxplot change line 48 to:
B = boxplot(x,group, 'positions', positions);
and change the header of the function to:
B = multiple_boxplot(data...
and save the function file.
This won't change anything in how the function works but will let you obtain a handle to the boxplot (B).
Then in your code, create the boxplot as before, but with the output argument B:
B = multiple_boxplot(data...);
And add the following lines:
% compute the mean by group:
M = cellfun(#mean,data);
% convert it to pairs of Y values:
M = mat2cell(repmat(M(:),1,2),ones(size(M,1),1),2);
% change the medians to means:
set(B(6,:),{'YData'},M)

define a series of matrices variables not using cell in Matlab

Here is my code:
A = zeros(10,10,10);
for i = 1:10
C{i} = A(:,:,i);
end
This is just a simple example and my question is: Is there any other way, NOT using a cell (C{i} in the code) to represent a series of 2D matrices variables (A(:,:,i) in the code) from a 3D matrix (A). Anyway I believe you will need some variable name like 'i'.
Thanks in advance!
You can do:
A = zeros(10,10,10);
for i = 1:10
eval(sprintf('A%d = A(:,:,%d)',i,i));
end
In this way you get 10 matrices whose names are A1, A2, ..., Ai,...
Anyway I suggest not using this method. It is more readable the one with cell arrays.

How can I view all elements of a structure of arrays without writing a FOR-loop?

I am interested in seeing all the elements in the :
result(:,:).randMin(1:4,2:end)
in which the result(a=1:24, d=1:5).
In general is it possible to access them without a loop and cat ?
You cannot use the [] trick with multi-level indexing, but if all of randMin are 128 x 11 arrays:
out = [result(1:24,1:5).randMin];
out = reshape(out,[128 11, 24, 5]);
out = out(1:4,2:end,:,:);
Final result has size of 4 x 10 x 24 x 5 where the first two are your randMin(1:4,2:end), and last two dimensions are your a and d respectively.
It looks like you are looking for getfield:
getfield( result, {1:24, 1:5}, 'randMin', {1:4, 2:end} );
I'm a bit rusty with this command and you might need to play with it a bit to make it work.
Read its manual and good luck!
I don't think it is possible because randMin could be something else for every field in result. result(1,1).randMin could be a matrix, result(1,2).randMin could be a vector, result(2,1).randMin could be 4-dimensional...you see where I'm going with this.
So there is no way of knowing the dimensions or the size of each result's randMin without looping through all fields in result. If there is a function that does what you want, it will have to use a loop internally, so you might as well use a loop yourself.
Edit:
If it is constant you can try something like this:
%Generating matrix struct results(a,b).randMin(c,d)
dim1=24;
dim2=5;
dim3=128;
dim4=11;
% value=0;
% for i=1:dim1
% for j=1:dim2
% for k=1:dim3
% for l=1:dim4
% results(i,j).randMin(k,l)=value;
% value=value+1;
% end
% end
% end
% end
%Getting the values
range1=1:24;
range2=1:5;
range3=1:4;
range4=2:dim4;
myMat=[results(range1, range2).randMin];
myContainer=reshape(myMat, dim3, dim4, length(range1), length(range2));
desiredValues=myContainer(range3, range4,:,:);
In the end, desiredValues will have the values you want, but the indices switched sides, instead of results(a,b).randMin(c,d) it is now desiredValues(c,d,a,b).
As I didn't know exactly how your struct looks like, I defined dim1 to dim4 as maximum values for the indices a to d. You can use range1 to range4 to select your desired values.

How to write this in an elegant way (cell arrays and structs in MATLAB)

I would like to plot connected points in MATLAB.
My connected points come from connecting objects of "stats", where each "stat" comes from a BW regionprops struct.
The code I have written works, but it suffers from a lot of "ugliness", which I couldnt fix even after trying various ways.
function plot_line( line )
a = cell2mat(line);
b = {a.Centroid};
matx = {};
maty = {};
for i = 1:size(b,2)
matx{end+1} = b{i}(1);
maty{end+1} = b{i}(2);
end
plot ( cell2mat(matx), cell2mat(maty) );
end
Can you help me make this code nicer? It's not critical, as my code works fine and as the lines are short (<100 points) the performance is not an issue.
It is just that it would be really nice to know how this tiny function should be written in the proper way, without for loops and 3 calls of cell2mat.
In my example:
line is a <1xn cell>,
line{1} has a property 'Centroid' and
line{i}.Centroid(1) are the x coordinates and
line{i}.Centroid(2) are the y coordinates.
Actually, all I need is plotting line{i}.Centroid(1), line{i}.Centroid(2) for i = 1:size(line,2), but I don't know how.
Instead of creating a cell array b, you can create a numerical array directly, by catenating using CAT:
tmp = cat(1,line{:});
coordinates = cat(1,tmp.Centroid);
plot(coordinates(:,1),coordinates(:,2))
EDIT
If you want to keep it really short (i.e. even shorter than #Amro's solution you can use CELLFUN like this in order get a one-liner:
plot(cellfun(#(x)x.Centroid(1),line),cellfun(#(x)x.Centroid(2),line))
Example:
line = repmat({struct('Centroid',[1 2])},1,5); %# similar to the data you have
%# extract x/y coordinates
x = cellfun(#(s)s.Centroid(1),line)
y = cellfun(#(s)s.Centroid(2),line)
%# plot
plot(x,y)
You could also do it as:
xy = cell2mat(cellfun(#(s)s.Centroid, line, 'UniformOutput',false)');
plot(xy(:,1),xy(:,2))