Another question from the thick guy (me)... apologies - help much appreciated!
Here is an example sample from a larger matrix
0 1.0000 1.0000 60.0000 100.0000 0 0.2500
0 1.0000 1.0000 62.0000 100.0000 0.2500 0.2500
0 1.0000 1.0000 63.0000 100.0000 0.5000 0.2500
1.0000 1.0000 1.0000 58.0000 100.0000 0.7500 0.2500
1.0000 1.0000 1.0000 59.0000 100.0000 1.0000 0.2500
1.0000 1.0000 1.0000 65.0000 100.0000 1.2500 0.2500
2.0000 1.0000 1.0000 55.0000 100.0000 1.5000 0.2500
2.0000 1.0000 1.0000 57.0000 100.0000 1.7500 0.2500
2.0000 1.0000 1.0000 60.0000 100.0000 2.0000 0.2500
3.0000 1.0000 1.0000 54.0000 100.0000 2.2500 0.2500
3.0000 1.0000 1.0000 55.0000 100.0000 2.5000 0.2500
3.0000 1.0000 1.0000 59.0000 100.0000 2.7500 0.2500
4.0000 1.0000 1.0000 55.0000 100.0000 3.0000 0.2500
4.0000 1.0000 1.0000 56.0000 100.0000 3.2500 0.2500
4.0000 1.0000 1.0000 60.0000 100.0000 3.5000 0.2500
5.0000 1.0000 1.0000 53.0000 100.0000 3.7500 0.2500
5.0000 1.0000 1.0000 54.0000 100.0000 4.0000 0.2500
5.0000 1.0000 1.0000 59.0000 100.0000 4.2500 0.2500
6.0000 1.0000 1.0000 53.0000 100.0000 4.5000 0.2500
6.0000 1.0000 1.0000 56.0000 100.0000 4.7500 0.2500
6.0000 1.0000 1.0000 58.0000 100.0000 5.0000 0.2500
7.0000 1.0000 1.0000 58.0000 100.0000 5.2500 0.2500
7.0000 1.0000 1.0000 60.0000 100.0000 5.5000 0.2500
7.0000 1.0000 1.0000 65.0000 100.0000 5.7500 0.2500
8.0000 1.0000 1.0000 53.0000 100.0000 6.0000 0.2500
8.0000 1.0000 1.0000 54.0000 100.0000 6.2500 0.2500
8.0000 1.0000 1.0000 63.0000 100.0000 6.5000 0.2500
9.0000 1.0000 1.0000 61.0000 100.0000 6.7500 0.2500
9.0000 1.0000 1.0000 62.0000 100.0000 7.0000 0.2500
9.0000 1.0000 1.0000 65.0000 100.0000 7.2500 0.2500
etc....
For every z (the value of z has been prescribed earlier in the code) rows I'd like 3 copies of the rows to be inserted verbatim beneath them as follows (in this example z = 3) :
0 1.0000 1.0000 60.0000 100.0000 0 0.2500
0 1.0000 1.0000 62.0000 100.0000 0.2500 0.2500
0 1.0000 1.0000 63.0000 100.0000 0.5000 0.2500
0 1.0000 1.0000 60.0000 100.0000 0 0.2500
0 1.0000 1.0000 62.0000 100.0000 0.2500 0.2500
0 1.0000 1.0000 63.0000 100.0000 0.5000 0.2500
0 1.0000 1.0000 60.0000 100.0000 0 0.2500
0 1.0000 1.0000 62.0000 100.0000 0.2500 0.2500
0 1.0000 1.0000 63.0000 100.0000 0.5000 0.2500
0 1.0000 1.0000 60.0000 100.0000 0 0.2500
0 1.0000 1.0000 62.0000 100.0000 0.2500 0.2500
0 1.0000 1.0000 63.0000 100.0000 0.5000 0.2500
1.0000 1.0000 1.0000 58.0000 100.0000 0.7500 0.2500
1.0000 1.0000 1.0000 59.0000 100.0000 1.0000 0.2500
1.0000 1.0000 1.0000 65.0000 100.0000 1.2500 0.2500
1.0000 1.0000 1.0000 58.0000 100.0000 0.7500 0.2500
1.0000 1.0000 1.0000 59.0000 100.0000 1.0000 0.2500
1.0000 1.0000 1.0000 65.0000 100.0000 1.2500 0.2500
1.0000 1.0000 1.0000 58.0000 100.0000 0.7500 0.2500
1.0000 1.0000 1.0000 59.0000 100.0000 1.0000 0.2500
1.0000 1.0000 1.0000 65.0000 100.0000 1.2500 0.2500
1.0000 1.0000 1.0000 58.0000 100.0000 0.7500 0.2500
1.0000 1.0000 1.0000 59.0000 100.0000 1.0000 0.2500
1.0000 1.0000 1.0000 65.0000 100.0000 1.2500 0.2500
etc
Next I'd like column 1 to be replaced and to now have the pattern
[0 0 0 5 5 5 10 11 12 17 17 17 ]
which would then repeat (always from 5 integers later, until the end of the pattern so that the next 12 entries would be:
[22 22 22 27 27 27 32 33 34 39 39 39]
and so on.
It would be great if the code were relatively idiot-friendly (me-friendly) so
that I can easily manipulate this repeating pattern if need be. For example if z
were 4 rather than 3 then I would want the pattern
[0 0 0 0 5 5 5 5 10 11 12 13 18 18 18 18]
...Column 6 should then be replaced with a column that relates to column
1 in a (column_1 * 0.25) relationship.
i.e. for the above sample, where column 1 is:
[0 0 0 5 5 5 10 11 12 17 17 17 22 22 22 27 27 27 32 33 34 39 39 39]
column 6 would be:
[0 0 0 1.2500 1.2500 1.2500 2.5000 2.7500 3.0000 4.2500 4.2500 4.2500 5.5000
5.5000 5.5000 6.7500 6.7500 6.7500 8.0000 8.2500 8.5000 9.7500 9.7500
9.7500]
Can you help with that at all? Thanks very much in advance
TL;DR : For the final code : Go to section Full Code
The first part at least looks like a good job for reshape and repmat.
The tricky part is to not mess up with the dimensions.
Another approach will be to use cells and the function cellfun.
In this answer i will use a toy example defined as follow :
[~,ArrayIn]=meshgrid(1:7,1:20);
ArrayIn =
1 1 1 1 1 1 1
2 2 2 2 2 2 2
3 3 3 3 3 3 3
.....
z=3;
1. FIRST APPROACH : Use repmat and reshape :
Now, basically, the code will operate 3 major steps :
Step 1 : reshape the matrix so that it becomes a matrix of size size(ArrayIn,2)xzxsize(ArrayIn,1)/z
reshapedArrayIn=reshape(ArrayIn.',size(ArrayIn,2),z,[]);
Note that, after this step, the slices along the 3rd dimension are exactly the slices of length z that you want to repeat 3 times (only they are transposed, but it's needed because of the way reshape works).
reshapedArrayIn =
ans(:,:,1) =
1 2 3
1 2 3
1 2 3
1 2 3
1 2 3
1 2 3
1 2 3
ans(:,:,2) =
4 5 6
4 5 6
4 5 6
4 5 6
4 5 6
4 5 6
4 5 6
...
Also note that if the number of rows in your matrix is not dividable by z in the first place, the code will fail and you'll have to add extra lines before the call to reshape in order for it to work :
% Optional
if mod(size(ArrayIn,1),z)~=0
ArrayIn=[ArrayIn;zeros(z-mod(size(ArrayIn,1),z),size(ArrayIn,2))];
end
Step 2 : repeat the matrix 3 times along the second dimension
repArray=repmat(reshapedArrayIn,1,3,1);
Step 3 : reshape your matrix again in order to get a 2 dimensional matrix back, transpose the result to get it right
ArrayOut=reshape(repArray,size(ArrayIn,2),size(ArrayIn,1)*3).';
The result is as intended :
ArrayOut =
1 1 1 1 1 1 1
2 2 2 2 2 2 2
3 3 3 3 3 3 3
1 1 1 1 1 1 1
2 2 2 2 2 2 2
3 3 3 3 3 3 3
...
2. SECOND APPROACH : use cellfun
Another possibility to achieve this would be to convert you matrix to a cell and then use the function cellfun on all your subcells (This code would go after ArrayIn has been padded so that its number of rows is dividable by z:
Idy=7;
Idx=z*ones(size(ArrayIn,1)/z,1);
ArrayCell=mat2cell(ArrayIn,Idx,Idy);
CellOut=cellfun(#(A) repmat(A,3,1),ArrayCell,'UniformOutput',false);
ArrayOut=cell2mat(CellOut);
Giving also the expected result :
ArrayOut =
1 1 1 1 1 1 1
2 2 2 2 2 2 2
3 3 3 3 3 3 3
1 1 1 1 1 1 1
2 2 2 2 2 2 2
3 3 3 3 3 3 3
...
PART 2
For this part you can use what #tim gave you in the comments, although with a slight modification to take the length of your columns into account :
A = [zeros(1,z) 5*ones(1,z) 10:(9+z) 17*ones(1,z)];
m=ceil(size(ArrayOut,1)/(4*z));
UncutCol=repmat(A.',1,m)+repmat(22(*0:(m-1)),length(A),1);
Column1Out=UncutCol(1:size(ArrayOut,1));
Column6Out=Column1Out*0.25;
ArrayOut(:,1)=Column1Out;
ArrayOut(:,6)=Column6Out;
FULL CODE :
Approach 1 :
z=3;
[~,ArrayIn]=meshgrid(1:7,1:20);
if mod(size(ArrayIn,1),z)~=0
ArrayIn=[ArrayIn;zeros(z-mod(size(ArrayIn,1),z),size(ArrayIn,2))];
end
reshapedArrayIn=reshape(ArrayIn.',size(ArrayIn,2),z,[]);
repArray=repmat(reshapedArrayIn,1,3,1);
ArrayOut=reshape(repArray,size(ArrayIn,2),size(ArrayIn,1)*3).';
A = [zeros(1,z) 5*ones(1,z) 10:(9+z) 17*ones(1,z)];
m=ceil(size(ArrayOut,1)/(4*z));
UncutCol=repmat(A.',1,m)+repmat(22*(0:(m-1)),length(A),1);
Column1Out=UncutCol(1:size(ArrayOut,1));
Column6Out=Column1Out*0.25;
ArrayOut(:,1)=Column1Out;
ArrayOut(:,6)=Column6Out;
Approach 2 :
z=3;
[~,ArrayIn]=meshgrid(1:7,1:20);
if mod(size(ArrayIn,1),z)~=0
ArrayIn=[ArrayIn;zeros(z-mod(size(ArrayIn,1),z),size(ArrayIn,2))];
end
Idy=7;
Idx=z*ones(size(ArrayIn,1)/z,1);
ArrayCell=mat2cell(ArrayIn,Idx,Idy);
CellOut=cellfun(#(A) repmat(A,3,1),ArrayCell,'UniformOutput',false);
ArrayOut=cell2mat(CellOut);
A = [zeros(1,z) 5*ones(1,z) 10:(9+z) 17*ones(1,z)];
m=ceil(size(ArrayOut,1)/(4*z));
UncutCol=repmat(A.',1,m)+repmat(22*(0:(m-1)),length(A),1);
Column1Out=UncutCol(1:size(ArrayOut,1));
Column6Out=Column1Out*0.25;
ArrayOut(:,1)=Column1Out;
ArrayOut(:,6)=Column6Out;
Final Result :
ArrayOut =
0 1.0000 1.0000 1.0000 1.0000 0 1.0000
0 2.0000 2.0000 2.0000 2.0000 0 2.0000
0 3.0000 3.0000 3.0000 3.0000 0 3.0000
5.0000 1.0000 1.0000 1.0000 1.0000 1.2500 1.0000
5.0000 2.0000 2.0000 2.0000 2.0000 1.2500 2.0000
5.0000 3.0000 3.0000 3.0000 3.0000 1.2500 3.0000
10.0000 1.0000 1.0000 1.0000 1.0000 2.5000 1.0000
11.0000 2.0000 2.0000 2.0000 2.0000 2.7500 2.0000
12.0000 3.0000 3.0000 3.0000 3.0000 3.0000 3.0000
17.0000 4.0000 4.0000 4.0000 4.0000 4.2500 4.0000
17.0000 5.0000 5.0000 5.0000 5.0000 4.2500 5.0000
17.0000 6.0000 6.0000 6.0000 6.0000 4.2500 6.0000
22.0000 4.0000 4.0000 4.0000 4.0000 5.5000 4.0000
22.0000 5.0000 5.0000 5.0000 5.0000 5.5000 5.0000
22.0000 6.0000 6.0000 6.0000 6.0000 5.5000 6.0000
.....
I also want to provide a second solution, everything you need to know is provided as comments:
%%% INPUT DATA %%%
N = 3;
[~, A]=meshgrid(1:7,1:21);
numRows = size(A, 1);
if(mod(numRows, N) ~= 0)
% do padding here so that numRows can be devided by N, you can do it yourself :-)
end
%%% FIRST PART %%%
cnt = reshape(1:numRows,[N, numRows/N]) % create matrix which contains indices 1:numRows (number of Rows of A) in the desired manner
idx = repmat(cnt, N+1, 1) % number of copies of every line you want: N (so you'd have N+1 entries of every row (1 base and N copies))
A_cop = A(idx(:), :) % now idx(:) will give you the row-indices to replicate the rows of A in the desired manner
% --> 3-liner :-) could even be summed up in one single codeline :D
%%% SECOND PART %%%
c = [zeros(1,N) 5*ones(1,N) 10:(9+N) 17*ones(1,N)]; % base format
c2 = repmat(c', 1, ceil(size(A_cop, 1)/length(c))); % replicate it so that +i*22 can be added easily column-wise (i=column index)
c3 = bsxfun(#plus, c2, [(0:(size(c2,2)-1))]*22);
firstCol = c3(:); % linearize column-major memory
%%% THIRD PART -> merge both parts %%%
A_cop(:, 1) = firstCol(1:size(A_cop,1)); % set first column
A_cop(:, 6) = A_cop(:, 1)*0.25;
I think my first part might be a bit easier to understand then the solution from Bill, isnt it?
Im using indexing to copy rows within the input matrix A. That means, I generate a vector which contains the row-indices which I want to take from A, and this vector can contain values multiple times.
My example index-vector looks like this:
>> idx(:)
ans =
1
2
3
1
2
3
1
2
3
1
2
3
4
5
6
4
5
6
4
5
6
4
5
6
7
8
9
...
Using this, I make the final matrix A_cop and afterwards I apply the second part as described above in the comment --> replicate the base format c in a matrix and sum +i*22 in the i-th column, then linearizing the memory to yield one row-vector :-)
I have this matrix that is ready to be plotted in "Matlab" with scatter3, if the following command is used
scatter3( F(:,[1]) , F(:,[2]) , F(:,[3]) , F(:,[4]) , F(:,[5]) )
(I am basically splitting the F matrix in 5 column vectors)
F =
52.5000 12.6000 288.0000 20.0000 1.0000
52.5000 6.3000 408.0000 20.0000 1.0000
52.5000 4.8000 467.0000 20.0000 1.0000
52.5000 3.5000 559.0000 20.0000 1.0000
52.5000 2.0000 730.0000 20.0000 1.0000
52.5000 1.3000 902.0000 20.0000 1.0000
26.2500 12.6000 203.0000 20.0000 2.0000
26.2500 6.3000 288.0000 20.0000 2.0000
26.2500 4.8000 332.0000 20.0000 2.0000
26.2500 3.5000 389.0000 20.0000 2.0000
26.2500 2.0000 516.0000 20.0000 2.0000
26.2500 1.3000 637.0000 20.0000 2.0000
10.0000 12.6000 125.0000 20.0000 3.0000
10.0000 6.3000 177.0000 20.0000 3.0000
10.0000 4.8000 204.0000 20.0000 3.0000
10.0000 3.5000 240.0000 20.0000 3.0000
10.0000 2.0000 318.0000 20.0000 3.0000
10.0000 1.3000 392.0000 20.0000 3.0000
5.0000 12.6000 88.0000 20.0000 4.0000
5.0000 6.3000 125.0000 20.0000 4.0000
5.0000 4.8000 144.0000 20.0000 4.0000
5.0000 3.5000 169.0000 20.0000 4.0000
5.0000 2.0000 224.0000 20.0000 4.0000
5.0000 1.3000 277.0000 20.0000 4.0000
2.0000 12.6000 55.0000 20.0000 5.0000
2.0000 6.3000 78.0000 20.0000 5.0000
2.0000 4.8000 90.0000 20.0000 5.0000
2.0000 3.5000 106.0000 20.0000 5.0000
2.0000 2.0000 141.0000 20.0000 5.0000
2.0000 1.3000 175.0000 20.0000 5.0000
1.0000 6.3000 55.0000 20.0000 6.0000
1.0000 4.8000 63.0000 20.0000 6.0000
1.0000 3.5000 75.0000 20.0000 6.0000
1.0000 2.0000 99.0000 20.0000 6.0000
1.0000 1.3000 123.0000 20.0000 6.0000
0.5000 6.3000 38.0000 20.0000 7.0000
0.5000 4.8000 44.0000 20.0000 7.0000
0.5000 3.5000 52.0000 20.0000 7.0000
0.5000 2.0000 70.0000 20.0000 7.0000
0.5000 1.3000 86.0000 20.0000 7.0000
If you plot this you'll see that the points are grouped in 7 same coloured groups (taken from column 5 of the F matrix).
I would like to plot lines connecting the same coloured points. Of course the lines should have the same colour as the points they connect.
I have attempted to split the F matrix in five 6x5 matrices (named F1-F5) and 2 5x5 matrices (named F6 and F7) and use scatter3() along with line() commands and hold on to create my 3D graph, but it did not do what I wanted.
For every new set of points that is plotted with scatter3() the sets of points already plotted change colour. So assigning a short name colour in the line() function does not help.
What options do I have? Perhaps scatter3 is not the best function to use in this case?
EDIT
plot3() is promising , but has a limited color set. Indeed I would prefer to avoid using colours "white" and "yellow", which do not show up nice on white background.
So, I will assume you are going to separate your matrices into 7, in this case, and save them in a cell array, as dynamic variables are BAD!
Assuming you have a cell array called F this works:
C=hsv(7);
hold on
for ii=1:size(F,2)
% //plot lines
plot3(F{ii}(:,1),F{ii}(:,2),F{ii}(:,3),'Color',C(ii,:));
% // plot points
plot3(F{ii}(:,1),F{ii}(:,2),F{ii}(:,3),'.','MarkerSize',F{ii}(1,4),'Color',C(ii,:));
end
The only problem it has is that it doesnt allow for multiple marker sizes, so if you want the points to have different marker sizes, you'd need to add another loop and go plotting the points one by one. I hope you are able to get it from here ;)
I have 3 vectors: npdf, tn(:,1) and tn(:,2) and am finding the values of npdf in tn(:,2) line by line:
[npdf(1:20,1), tn(1:20,:)]
ans =
8.0000 3.0000 1.0000
11.0000 2.9167 1.0000
1.0000 3.3000 1.0000
11.0000 1.2167 1.0000
5.0000 2.8167 1.0000
1.0000 2.4000 1.0000
2.0000 2.4500 1.0000
4.0000 0.2500 1.0000
15.0000 3.7500 1.0000
15.0000 4.9167 1.0000
1.0000 2.8167 2.0000
17.0000 0.2500 2.0000
15.0000 1.0000 3.0000
4.0000 3.0000 3.0000
8.0000 0.5833 3.0000
1.0000 0.5833 3.0000
3.0000 5.0000 5.0000
11.0000 3.7500 6.0000
8.0000 3.0000 7.0000
15.0000 2.8000 7.0000
for i=1:length(npdf)
[LOCA,~]=ismember(tn(:,2),npdf(i,1,1));
dummy=find(LOCA~=0);
tpdf(i,1)=tn(randi(length(dummy),1,1),1);
end
each time it finds the value of npdf in tn(:,2) it chooses a value from tn(:,1).
Here's the problem: if it can't locate the value from npdf in tn(:,2) then I need to choose the nearest value (in magnitude) in tn(:,2) and proceed. Either that or some sort of interpolation between nearest values.. How would you do this most efficiently?
At your discretion to change the code, it doesn't look very efficient to me.
It can be done easily by using knnsearch as follows:
[idx,D]=knnsearch(tn(:,2),npdf,'K',size(tn,1));
for i=1:size(D,1)
tpdf(i,1)=tn(randi(sum(D(i,:)==min(D(i,:))),1,1),1);
end
It finds distance of each value in npdf to all the values in tn. Then it considers only the nearest value. Then it selects a random indices from tn(:,1) as per your code.
I have following data matrix, I want to iterate over this matrix and look at a value in the last column based on a given row and add that row - last element of that row to a new matrix.
5.1000 3.3000 1.7000 0.5000 1.0000
6.8000 3.2000 5.9000 2.3000 3.0000
5.0000 2.3000 3.3000 1.0000 2.0000
7.4000 2.8000 6.1000 1.9000 3.0000
6.5000 3.2000 5.1000 2.0000 3.0000
4.8000 3.4000 1.9000 0.2000 1.0000
4.9000 3.0000 1.4000 0.2000 1.0000
5.1000 3.8000 1.5000 0.3000 1.0000
5.1000 3.4000 1.5000 0.2000 1.0000
5.5000 2.6000 4.4000 1.2000 2.0000
This is the code that I have
M1 = [];
M2 = [];
M3 = [];
for i=1:length(currentCell)
if currentCell(1,5) == 1.00
m3Data = currentCell(1:1,1:4);
%how can I add m3Data to M1
end
end
Let your original matrix be M, then this
M1 = M(find(M(:,5)==1),1:4)
puts all the rows ending with a 1 into M1, excluding the final column. Is that what you want ?
You could do it with a for loop if you want, but I don't see any need.
I have a matrix (table actually) which I imported from a file:
1.0000 1.9736
4.0000 0.2016
9.0000 0.0584
10.0000 0.0495
5.0000 0.1845
2.0000 0.6873
1.0000 1.4177
2.0000 0.4699
5.0000 0.1555
10.0000 0.0435
13.0000 0.0326
8.0000 0.0860
5.0000 0.1685
4.0000 0.1956
5.0000 0.1433
8.0000 0.0675
13.0000 0.0335
13.0000 0.0327
10.0000 0.0431
9.0000 0.0582
10.0000 0.0551
13.0000 0.0308
I want to get the average of each of the occurance on left column. That is:
avg = [
1.0000 1.69565
2.0000 0.5786
4.0000 0.1978]
and so on. I could do this with a wile or for group but this is not the matlab way. So how can I do this?
a=[randi(5,10,1) rand(10,1)];
a =
4.0000 0.4387
1.0000 0.3816
2.0000 0.7655
1.0000 0.7952
1.0000 0.1869
5.0000 0.4898
4.0000 0.4456
2.0000 0.6463
5.0000 0.7094
1.0000 0.7547
[uniqueID,~,uniqueInd]=unique(a(:,1));
[uniqueID accumarray(uniqueInd,a(:,2))./accumarray(uniqueInd,1)]
ans =
1.0000 0.5296
2.0000 0.7059
4.0000 0.4422
5.0000 0.5996
If your matrix is called a, try
>> accumarray(grp2idx(a(:,1)),a(:,2),[],#mean)
ans =
1.6957
0.5786
0.1986
0.16295
0.07675
0.0583
0.0478
0.0324
Note that grp2idx is part of Statistics Toolbox. If you don't have that, you can use the unique command to get the same results.