Multiple boxplot with unequal length in MATLAB - matlab

Below is the MATLAB code that i used to plot multiple boxplots in one figure. However, this only works if the data is of equal length (n1,n2,n3,n4,n5,n6 =10 in this example). How do i change this so that it works for dataset with unequal length? For example: n1=10, n2=10, n3=15,n4=15,n5=5,n6=5?
clc
clear
n1=10;n2=10;n3=10;n4=10;n5=10;n6=10;
x=[rand(1,n1) rand(1,n2) rand(1,n3) rand(1,n4) rand(1,n5) rand(1,n6)];
n=10 ; xx=([1:6])'; % example
r=repmat(xx,1,n)';
g=r(:)';
positions = [1 2 3 4 5 6 ];
h=boxplot(x,g, 'positions', positions);
set(h,'linewidth',2)
set(gca,'xtick',[mean(positions(1:2)) mean(positions(3:4)) mean(positions(5:6)) ])
set(gca,'xticklabel',{'exp1','exp2','exp3'},'Fontsize',28)
color = ['c', 'y', 'c', 'y','c', 'y'];
h = findobj(gca,'Tag','Box');
for j=1:length(h)
patch(get(h(j),'XData'),get(h(j),'YData'),color(j),'FaceAlpha',.5);
end

clearvars
n1=10;n2=10;n3=15;n4=15;n5=5;n6=5;
A=zeros(n1,1);A=num2str(A);A(1:end)='1';
B=zeros(n1,1);B=num2str(B);B(1:end)='2';
C=zeros(n1,1);C=num2str(C);C(1:end)='3';
D=zeros(n1,1);D=num2str(D);D(1:end)='4';
E=zeros(n1,1);E=num2str(E);E(1:end)='5';
F=zeros(n1,1);F=num2str(F);F(1:end)='6';
x=[rand(1,n1) rand(1,n2) rand(1,n3) rand(1,n4) rand(1,n5) rand(1,n6)];
boxplot([x(1,1:n1)';x(1,n1+1:n1+n2)';x(1,n1+n2+1:n1+n2+n3)';x(1,n1+n2+n3+1:n1+n2+n3+n4)';...
x(1,n1+n2+n3+n4+1:n1+n2+n3+n4+n5)';x(1,n1+n2+n3+n4+n5+1:n1+n2+n3+n4+n5+n6)'],[A;B;C;D;E;F])

There are a couple issues with your code that cause it to fail. Check my code below which you should be able to replace with yours. Rather than having to specify n1,n2,...etc., put all n-values in an array. Note your set functions will not work if you change the number of elements in ns from 6, but my code on its own will. In the future, I suggest generalizing your code to be less dependent on such things, and define less variables.
ns=[20,7,16,5,6,7]; %rather than specifying all your n variables individually, put them in an array
x=rand(1,sum(ns(:))); %allocates membory for x
ns=[0,ns]; %used for easier indexing in for loop
for(i=2:length(ns))
g((1+sum(ns(1:(i-1)))):(ns(i)+sum(ns(1:(i-1)))))=repmat(i-1,1,ns(i)); % populates g array
end
positions=1:(length(ns)-1);
h=boxplot(x,g,'positions',positions)
or, if it makes more sense to you, you could replace
ns=[0,ns]; %used for easier indexing in for loop
for(i=2:length(ns))
g((1+sum(ns(1:(i-1)))):(ns(i)+sum(ns(1:(i-1)))))=repmat(i-1,1,ns(i)); % populates g array
end
with
g=[];
for(i=1:length(ns))
g=[g repmat(i,1,ns(i))];
end
though this is generally bad practice as the size of g changes with every loop,so Matlab may throw a warning if your ns get too big.

Related

How to avoid sub2ind and decrease execution time in manipulating multidimensional arrays using original indexes

I would like your suggestions to make my code faster (and elegant). In particular, sub2ind (and the if-loop) slow it down dramatically according to the matlab profiler. I will try to explain what I need from my code as simply as I can.
Assuming I have the following problem, for simplicity.
Every citizen of every city has a car of a specific brand and a specific color.
What I would like to have is a 4D multidimensional array Data_4D(City,Citizen,Car_brand,Car_color) that I can manipulate (read and modify) using as indexes only these four dimensions.
Then, I want to reshape my multidimensional array into a 1D array Data_1D with
length(Data_1D)=(City*Citizen*Car_brand*Car_color)
The order of the elements must follow an indexing rule:
Example assuming City=2, Citizen=2, Car_brand=2, Car_color=2;
Data_1D(1)=Data_4D(1,1,1,1)
Data_1D(2)=Data_4D(1,1,1,2)
Data_1D(3)=Data_4D(1,1,2,1)
Data_1D(4)=Data_4D(1,1,2,2)
Data_1D(5)=Data_4D(1,2,1,1)
Data_1D(6)=Data_4D(1,2,1,2)
Data_1D(7)=Data_4D(1,2,2,1)
Data_1D(8)=Data_4D(1,2,2,2)
Data_1D(9)=Data_4D(2,1,1,1)
Data_1D(10)=Data_4D(2,1,1,2)
Data_1D(11)=Data_4D(2,1,2,1)
Data_1D(12)=Data_4D(2,1,2,2)
Data_1D(13)=Data_4D(2,2,1,1)
Data_1D(14)=Data_4D(2,2,1,2)
Data_1D(15)=Data_4D(2,2,2,1)
Data_1D(16)=Data_4D(2,2,2,2)
After that I will get this 1D array, shaped as above, I need to create a matrix Matrix_Final( NRows,length(Data_1D)) in which every row is an array Data_1D. In every row NRows, the array Data_1D will have the same amount of elements but with different values.
The amount of rows depends also on some (or all) of the four the dimensions City,Citizen,Car_brand,Car_color (respecting the same indexing rule as for Data_1D) and the array built in each line must be manipulated according also to the value of the matrix row (by using the four indexes, which is the common rule for both NRows and Data_1D).
Example:
Assuming City=2, Citizen=2, Car_brand=2, Car_color=2;
Assuming NRows depends on all the four dimensions.
I will have Matrix_Final( length(DATA_1D), length(DATA_1D)).
I want that all the data of my array DATA_1D are zeros, except one element, which has to be the element that has the same indexes values(City,Citizen,Car_brand,Car_color) as NRows(City,Citizen,Car_brand,Car_color)
So at the row NRows(1), only Data_1D(1) is non-zero. For this example, the result is an eye matrix.
clc
clear all
%Dimensions Definition
City=2;
Citizen=2;
Car_brand=2;
Car_color=2;
%Length of Data
Length_Data_1D=City*Citizen*Car_brand*Car_color;
%preallocation Matrix_Final
Matrix_Final=zeros(City*Citizen*Car_brand*Car_color, Length_Data_1D);
%indexes of the dimensions
indexes_array_carcolor=repmat(repelem([1:Car_color], 1), [1 City*Citizen*Car_brand]);
indexes_array_carbrand=repmat(repelem([1:Car_brand], Car_color), [1 City*Citizen]);
indexes_array_citizen=repmat(repelem([1:Citizen],Car_brand*Car_color),[1 City]);
indexes_array_city=repmat(repelem([1:City],Citizen*Car_brand*Car_color),[1 1]);
%Initializing loop variable
column_Matrix_final=1;
for CITY_selected=1:City
for CITIZEN_selected=1:Citizen
for CAR_BRAND_selected=1:Car_brand
for CAR_COLOR_selected=1:Car_color
%Data_4D Construction
Data_4D=zeros(City,Citizen,Car_brand,Car_color);
for city=1:length(indexes_array_city)
for citizen=1:length(indexes_array_citizen)
for car_brand=1:length(indexes_array_carbrand)
for car_color=1:length(indexes_array_carcolor)
if (indexes_array_city(city)==CITY_selected && indexes_array_citizen(citizen)==CITIZEN_selected ...
&& indexes_array_carbrand(car_brand)==CAR_BRAND_selected && ...
indexes_array_carcolor(car_color)==CAR_COLOR_selected)
Data_4D(sub2ind(size(Data_4D),indexes_array_city(city),indexes_array_citizen(citizen),...
indexes_array_carbrand(car_brand), indexes_array_carcolor(car_color)))=1;
end
end
end
end
end
%Data_4D transformation into array Data_1D
Data_1D=zeros(1,City*Citizen*Car_brand*Car_color);
tic=1;
for city=1:City
for citizen=1:Citizen
for car_brand=1:Car_brand
for car_color=1:Car_color
Data_1D(tic)=Data_4D(city,citizen,car_brand,car_color);
tic=tic+1;
end
end
end
end
%Adding Data_1D to the next for of Matrix_Final
Matrix_Final(column_Matrix_final,:)=Data_1D;
column_Matrix_final=column_Matrix_final+1;
%Display of the four most external loops indexes to show code
%advancement
CAR_COLOR_selected
end
CAR_BRAND_selected
end
CITIZEN_selected
end
CITY_selected
end
spy(Matrix_Final)
If you add e.g.
&& indexes_array_carcolor(car_color)==2
in the if loop, only the elements of Data_1D(City,Citizen,Car_brand,Car_color=2) in NRows(City,Citizen,Car_brand,Car_color=2) will be non-zero.
I would like to know if there are faster ways to set up the problem, but keeping the same ability to manipulate Data_1D an Matrix_Final using the four indexes (City,Citizen,Car_brand,Car_color) and the ability to correlate NRows and the elements of Data_1D using these four indexes.
Thank you for your help!
This is how you have coded it
if (indexes_array_city(city)==CITY_selected && indexes_array_citizen(citizen)==CITIZEN_selected ...
&& indexes_array_carbrand(car_brand)==CAR_BRAND_selected && ...
indexes_array_carcolor(car_color)==CAR_COLOR_selected)
Data_4D(sub2ind(size(Data_4D),indexes_array_city(city),indexes_array_citizen(citizen),...
indexes_array_carbrand(car_brand), indexes_array_carcolor(car_color)))=1;
end
Another way 1
if (indexes_array_city(city)==CITY_selected && indexes_array_citizen(citizen)==CITIZEN_selected ...
&& indexes_array_carbrand(car_brand)==CAR_BRAND_selected && ...
indexes_array_carcolor(car_color)==CAR_COLOR_selected)
Data_4D(indexes_array_city(city),indexes_array_citizen(citizen),...
indexes_array_carbrand(car_brand), indexes_array_carcolor(car_color))=1;
end
Another way 2
Data_4D(indexes_array_city(city),indexes_array_citizen(citizen),...
indexes_array_carbrand(car_brand), indexes_array_carcolor(car_color))=double((indexes_array_city(city)==CITY_selected)& ...
(indexes_array_citizen(citizen)==CITIZEN_selected)& ...
(indexes_array_carbrand(car_brand)==CAR_BRAND_selected)& ...
(indexes_array_carcolor(car_color)==CAR_COLOR_selected));
All three of them will yield same result. Try which is faster and use it.
%% Data_4D transformation into array Data_1D
Data_4D_size=size(Data_4D);
Data_1D_size=prod(Data_4D_size);
temp = permute(Data_4D, [4 3 2 1]);
Data_1D=reshape(temp,Data_1D_size,1);
Use this for 4D to 1D convertion
If still need more speed. Compile it to mex. Compiled code runs faster.

Using loops to get multiple values into a cell

I have 31 subjects (S1, S2, S3, S4, etc.). Each subject has 3 images, contrast1.img, contrast2.img, and contrast3.img. I would like to use a loop to get all paths to the contrasts from all the subjects into a nx1 cell called P. P should be something like this:
Data/S1/contrast1.img
Data/S1/contrast2.img
Data/S1/contrast3.img
Data/S2/contrast1.img
Data/S2/contrast2.img
Data/S2/contrast3.img
...
Data/S31/contast3.img
This is what I've tried:
A={'S1','S2','S3',...,'S31'}; % all the subjects
C={'contrast1.img','contrast2.img','contrast3.img'}; % contrast images needed for each subject
P=cell(31*3,1)
for i=1:length(A)
for j=1:length(C)
P{j}=spm_select('FPList', fullfile(data_path, Q{i}) sprintf('%s',cell2mat(C(j)))); % this is to select the three contrast images for each subject. It works in my script. It might not be 100% correct here since I had to simplify for this example.
end
end
This, however, only give me P with the 3 contrast images of the last subject. Previous subjects get overwritten. This indicates that the loop is wrong but I'm not sure how to fix it. Could anyone help?
No loop needed. Use ndgrid to generate the combinations of numbers, num2str with left alignment to convert to strings, and strcat to concatenate without trailing spaces:
M = 31;
N = 3;
[jj ii] = ndgrid(1:N, 1:M);
P = strcat('Data/S',num2str(ii(:),'%-i'),'/contrast',num2str(jj(:),'%-i'),'.img')
I would use a cell matrix, which directly represents the subject index and the contrast index.
To preallocate use P=cell(length(A),length(C)) and to fill it use P{i,j}=...
When you want to access the 3rd image of the 5th subject, use P{5,3}
The problem is where you assign P{j}.
Since j only loops 1:3 and doesn't care about i, you are just rewriting all three values for P{j}. I think you want to concatenate the new values to the cell array instead
for i=1:length(A)
for j=1:length(C)
P ={P; spm_select('FPList', fullfile(data_path, Q{i}) sprintf('%s',cell2mat(C(j))));}
end
end
or you could assign each value directly such as
for i=1:length(A)
for j=1:length(C)
P{3*(i-1)+j} =spm_select('FPList', fullfile(data_path, Q{i}) sprintf('%s',cell2mat(C(j))));
end
end

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.

Output loop result in Matlab

Hi have this code and I don't know how to put the output result with every pixel.I think the output code are not well defined.
EDIT:
I'm going to try to explain the code:
% I have an image
imagen1=imread('recor.tif');
imagen2= double(imagen1);
band1= imagen2(:,:,1);
% I preallocate the result (the image size is 64*89*6)
yvan2= zeros(61,89,1);
% For every pixel of the image, I want to get one result (each one is different).
for i = 1 : nfiles
for j = 1 : nrows
for i = 1:numel(band1)
% I'm doing this because I've to multiply the results of this interpolation with that result a2ldb1y= ldcm_1(:,1). This vector has a length of 2151x1 and I need to muliply the result of the interpolation for (101:267) position on the vector, this is the reason because I'm doing the interpolation since 101 to 267 (also because I don't have that values).
interplan= interp1(van1,man2,t2,'spline');
ma(96) = banda1a(i); % I said 96, because I want to do an interpollation
end
van1= [101 96 266]';
mos1= ma(134);
van2= [0 pos1 0];
t= 101:267;
t2= t';
xi= 101:1:267;
xi2=xi';
interplan= interp1(van1,van2,t2,'spline');
% After this, I 'prepare' the vector.
out=zeros(2151,1)
out(101:267) = interplan;
% And then, I do all this operation (are important for the result)
a2ldb1y= ldcm_1(:,1);
a2ldsum_pesos1= sum(a2ldb1y);
a2l7dout1_a= a2ldb1y.*out;
a2l7dout1_b= a2l7dout1_a./a2ldsum_pesos1;
a2l7dout1_c= sum(a2l7dout1_b);
% And the result a2l7dout1_c I want it for every pixel (the results are different because every pixel has a different value...)
**yvan2(:,:,1)= [a2l7dout1_c];**
end
end
Thanks in advance,
I'm shooting in the dark here, but I think you're looking for:
yvan2(i, j, 1)= a2l7dout1_c;
instead of:
yvan2(:,:,1)= [a2l7dout1_c];
and thus your output should be stored in the variable yvan2 after the loops are done.
P.S
Some issues in your code:
Why do you have two loops using the same iteration variable i? Your calculations are probably incorrect since i is being modified by two for loops.
Why do you even need the second loop? Each iteration overruns the value of ma(134) set by the previous iteration. You can just replace the entire loop with:
ma(134) = banda1a(numel(band1))
You shouldn't be using the names i and j for loop variables. They are already reserved for the imaginary unit (that is, sqrt(-1)), so MATLAB needs extra processing time for name resolution. You'd rather use other loop variable names instead, even ii and jj.

Mark values from loop for each iteration

I want to mark each value that comes out of my loop with a value.
Say I have a variable number of values that come out of each iteration. I want those values to be labeled by which iteration they came out of.
like
1-1,
2-1,
3-1,
1-2,
2-2,
3-2,
4-2,
etc.
where the first number is the value from the loop and the second is counting which iteration it came from.
I feel like there is a way I just cant find it.
ok so here is some code.
for c=1:1:npoints;
for i=1:1:NN;
if ((c-1)*spacepoints)<=PL(i+1) && ((c-1)*spacepoints)>=PL(i);
local(c)=((c)*spacepoints)-PL(i);
end
if ((c-1)*spacepoints)>=PL(NN);
local(c)=((c)*spacepoints)-PL(NN);
element(i)=NN;
end
end
I want to mark each local value with the iteration it came from for the i:NN. PL is a vector and the output is a set of vectors for each iteration.
For this sort of quick problem I like to create a cell array:
for k = 1:12
results{k} = complicated_function(...);
end
If the output is really complicated, then I return a struct with fields relating to the outputs:
for k = 1:12
results{k}.file = get_filename(...);
results{k}.result = ...;
end
Currently as it is right now, in your inner 1:NN loop, your local(c) variable is being updated or overwritten. You never apply the previous value of local, so it is not some iterative optimization algorithm(?)...
Perhaps an easy solution is to change the size/type of local from a vector to a matrix. Let's say that local is of size [npoints 1]. Instead you make it of size [npoints NN]. It is now a 2d-array (a matrix of npoints rows and NN columns). use the second dimension to store each (assumed column) vector from the inner loop:
local = zeros([npoints NN]);
%# ... code in bewteen ...
for c=1:1:npoints;
for i=1:1:NN;
if ((c-1)*spacepoints)<=PL(i+1) && ((c-1)*spacepoints)>=PL(i);
local(c, i)=((c)*spacepoints)-PL(i);
end
if ((c-1)*spacepoints)>=PL(NN);
local(c, i)=((c)*spacepoints)-PL(NN);
element(i)=NN;
end
end
end
The c'th row of your local matrix will then corresponds to the NN values from the inner loop. Please note that I have assumed your vector to be a column vector - if not, just change the order of the sizes.