Unable to replace values in a matrix - matlab

I'm currently working on a cellular automata but i keep running into this problem. I have a matrix idxR which contains zero's and/or ones, depending on a probability process:
idxR = ((rRecr>rEmpty)&(rRecr>rAlgae)&(rRecr>rCoral));
Now i want to replace all ones in idxR with unique values and assign it to the variable colonies. I came up with the following:
colonies = idxR;
no = sum(colonies(:)==1)
maxvalue = max(colonies(:));
replace = [1:no]+maxvalue;
ret = reshape(replace,no,1);
colonies(colonies==1) = colonies(colonies==1).*ret;
When i output colonies it gives me a matrix with just ones and zeros and not a matrix where all ones have been replaced with incremental values. I tried this code in a new file and assigned a matrix with random ones and zeros to idxR and then it seems to work. So i guess to problem lies with the matrix idxR in my automata. It might be worth mentioning that idxR is contained in a for loop.
Can somebody tell me how to fix this?

You got the entire logic correct, except one minor flaw. You have idxR as a logical matrix. Hence colonies is a logical matrix too. Therefore, you get the expected output till the second-last line. Problem occurs on the last line, when you try to assign an array of numbers in which each number is greater than 1 (colonies(colonies==1).*ret;) to a logical matrix.
Elements greater than 1 are clipped to one and thus you see only zeros and ones. There is a simple workaround. Change the first line to
colonies = double(idxR);
P.S. The answer was right in front of you, you just didn't spot it. You had written:
I tried this code in a new file and assigned a matrix with random ones and zeros to idxR and then it seems to work.
The idxR matrix must have been of double datatype, if you used randi.

Parag got it right. You have the solution there.
You can use the following code if you are looking for a more "organized" way to get to 'colonies' -
colonies = double(idxR);
maxvalue = max(colonies(:));
ind1 = find(idxR==1);
colonies(ind1)=maxvalue + (1:numel(ind1));

Related

Appending a row/column of different size to an array.

Recently, I came across this behaviour in Matlab and I am curious as to know why this happens.
a(1,:) = rand(4,1);
a(2,:) = rand(5,1);
This throws me Subscripted assignment dimension mismatch. error whereas
a(1,:) = rand(4,1);
a(2,1:5) = rand(5,1);
adjusts the array to the max column size and appends zero to the shorter ones.
My question is: Why the former code snippet doesn't do what the latter does(which seems very logical to me)? I don't see any reason as to why the former code snippet should work the way it does. Or am I missing something?
With a(2,:) = rand(5,1);, you are attempting to assign a 5x1 vector to a 4x1 matrix column. Hence the error.
With a(2,1:5) = rand(5,1);, you are explicitly referencing a 5th row, which tells the Matlab engine to expand the matrix accordingly before attempting the assignment operation. Hence, this will succeed.
The way I see it, trying to put 5 values into a 4 row vector likely comes from an error in the code, so the user has to explicitly state that this is what he intends to do. Of course, I can only infer on the intent of Mathworks developers when they specifiy the behavior of their language.

How to sum a matrix with unaligned elements?

I am trying to sum in the second dimension a matrix QI in Matlab. The trick is, the columns contain a series of increasing numbers, but not all columns have the same number of elements (i.e. numel(QI(:,1)) ~= numel(QI(:,2)) and so on). For the sake of clarity, I attach a picture of it. Note that I padded the missing areas with 0, so the previous condition becomes nnz(QI(:,1)) ~= nnz(QI(:,2)).
One initial strategy that I thought of was to treat this as an image and construct a mask for each different gradient level, but that seems like a tedious job.
Anyone has a better idea on how to do this? I should also mention that I am able to freely modify how QI is generated, but I'd rather not if there is a solution for this problem.
EDIT:
Hopefully the new colored image should give a better understanding.
FYI, each column was previously stored in a cell array without the trailing zeros. Then I extracted the columns one by one and stored them in a matrix in order to perform the summation, padding the extra zeros whenever the length isn't the same.
Generally these column data should have the same number of rows, but sometimes that's not the case, and even worse, they do not allign properly.
I'm starting to think if it's better to rework the code that generate the cell arrays rather than this matrix. Thoughts?
Thank you,
edit: following you comment, I modified the answer. Be aware that your data cannot be really "aligned" because they have not the same number of value.
A way would be to use a cell as a storage for your measures.
valueMissing = 0; % here you can put the defauld value you want
% transform you matrix in a cell
QICell = arrayfun(#(x) QI(QI(:,x)!=valueMissing,x), 1:size(QI,2),'UniformOutput', false);
Now you can sum the last element of the vectors inside the cell
QIsum = sum(cellfun(#(x) x(end), QICell))
Or reorder the vectors so that your last element are "aligned"
QICellReordered = cellfun(#(x) x(end:-1:1),QICell, 'UniformOutput',false);
Then you can make all possible sums:
m = min(cellfun(#numel, QICellReordered));
QIsum = zeros(m,1);
for i=1:m
QIsum(i) = sum(cellfun(#(x) x(i), QICellReordered));
end
% reorder QISum to your original order
QIsum = QIsum(end:-1:1);
I hope this help !

Assigning arrays to a matrix in a function, syntax problems

I'm having trouble with the syntax in Matlab.
I'm trying to split an audio signal up into different segments (frames).
I would like to return the y-axis values to a matrix (each segment having its own column), and the corresponding time values with each segment having its own row.
I can't even get it to return just one single column and row pair (ie one frame). I just get returned two empty matrices. Here's my code.
function [mFrames, vTimeFrame] = Framing(vSignal,samplingRate,frameLPerc,frameshPerc)
totalTime=size(vSignal,1)/samplingRate
frameLength = totalTime*frameLPerc;
frameShift = totalTime*frameshPerc;
frameNumber =0;
check=frameLPerc;
while check<1
check = check+frameshPerc;
frameNumber=frameNumber+1;
end
start = 1;
% problem part
mFrames = vSignal(round((start:1/samplingRate:frameLength)*samplingRate));
vTimeFrame = round((start:1/samplingRate:frameLength)*samplingRate);
end
In the end I would like to be able to segment my entire signal into mFrames(i) and vTimeFrame(i) with a for-loop, but never mind that I cannot even get my function to return the first one (like I said empty matrix).
I know my segment code should be correct because I've got another script working with the same vSignal (it's a column vector by the way) that works just fine (y==vSignal):
voiced = y(round((1.245:1/Fs:1.608)*Fs));
plot(1.245:1/Fs:1.608,voiced)
I titled this with syntax problems because I'm very new to matlab and am used to Java. It feels very weird not initializing anything, and so I'm unsure whether my code is actually making any sense.
When testing I enter [m1,m2]=Framing(y,16000,0.1,0.05).
I got it.
start was not in the right domain. This is correct:
round((start/samplingRate:1/samplingRate:frameLength)*samplingRate)
When I plot(m2,m1) I now get the correct answer.
I do still have another question though, how can I assign these segments to my matrices?
for i=1:frameNumber
mFrames(:,i) = vSignal(round((start/samplingRate:1/samplingRate:frameLength)*samplingRate));
vTimeFrame(i) = round((start/samplingRate:1/samplingRate:frameLength)*samplingRate);
start=start+frameShift;
frameLength=frameLength+frameShift;
end
I get this error
In an assignment A(I) = B, the number of elements in B and I must be the same.
Like I said I'm trying to get the y-axis numbers in columns next to each other and the x-axis in rows.

copy looping matrixes into one 3-d matrix

I have a list of text files that I would like to load, and then extract rows where they all overlap. The first column contains years and each data set spans a different chunk of years but they all overlap in the middle. In the end I would like to have a three dimensional matrix with the overlapping years in one matrix. My code keeps getting stuck at the line that I have commented out. I know its incorrect but could anyone tell me why it is incorrect?
clear all
name_list = {'Beijing';'GT';'soi';'naoi';'Sydney_Airport';'Los Angeles';'Paris';'Presque Isle'};
[m,n] = size(name_list);
files = dir('*.txt');
[m,n] = size(files);
for i=1:m
eval(['load ' files(i).name ' -ascii']);
vals{i} = load(files(i).name);
matrix = vals{i};
station = (files(i).name(1:end-4));
startyear(i) = min(matrix(:,1));
endyear(i) = max(matrix(:,1));
allstart = max(startyear);
allend = min(endyear);
%matrixnew(i) = matrix(allstart:allend,2:13,i);
end
Two problems here:
Your commented line %matrixnew(i) = matrix(allstart:allend,2:13,i); assumes that matrix is a 3-d array, but elsewhere you treat it as 2-d (and I believe that load always returns a 2-d array). This could be why you are getting the "Index exceeds matrix dimensions" error. Example:
>> foo = rand(10,10);
>> foo(2:10,3:4,2)
Index exceeds matrix dimensions.
Maybe you want matrix(allstart:allend,2:13)? But that won't work, because allstart contains a year, which presumably will not be a valid index for the array (a more likely cause of your error). Using the index that contains the smallest value would be closer to being correct, but I think it still won't work.
matrixnew refers to a single element of an array. You can't assign an array to an element of an array. grantnz is right that making matrixnew a cell array would fix this error, and I guess that in the end you could turn your cell array into 3-d array.
I think you are on the right track, but are missing a few pieces to making this work. One thing to consider is that it looks like you are trying to do everything in a single pass. I don't see how that can work. You need to real all files before you can decide which range of years to keep. So do it in multiple passes: first load all data from all files into a cell array, then figure out the range of years, then pull the data from each file for that range of years.

error message on the dimensions of matrix in Matlab

When I run this program, I get the error message:
??? Index exceeds matrix dimensions.
Error in ==> if a(1,i)==0
could you tell me why??
a = randi(5,4,100)-ones(4,100);
[n m]=size(a);
for i=1:m
if a(1,i)==0
a(:,i)=[];
end
end
The reason is that you are removing columns from your matrix, so inside the for loop you are reducing its dimension. Then you try to access a column with an index which refers to the original matrix, before the columns were removed.
Try this instead:
a = randi(5,4,100)-1;
ind2remove = (a(1,:) == 0);
a(:,ind2remove) = [];
You get that error because during the execution of this for loop, you might remove some columns. Therefore the dimensions of the matrix will decrease and you will try to access elements that have been moved to a different place.
To do wht you want, you either have to write a while loop, keeping the indices in check manually. The other solution is to vectorize your solution as itamar Katz has shown. That solution is more MATLAB-esque than writig a while loop.
But I have noticed that allowing a random algorithm to emit vectors of random length can sometimes prove more difficult to handle than fixed-length vectors. So you might want to construct your vector in such a way that you don't even have to remove such entries, depending on your application this might be accomplished by generating the first row and other rows with different instructions.