How to update values from rows on a matrix - matlab

I have a matrix: 6 rows x 18 columns
and I want to ask the user which row he wants to change to 0 and make it happen, but if he inputs 0 it just exits the program
row = input('Input 0 to exit\n\n Row to eliminate:', 's');
if row ~= 0
M(row,:) = 0;
disp(M)
end
I want to to change the whole input row to 0, but it somehow creates 44 more rows below the original matrix (all 0) and doesn't change the first 6 rows(original matrix)

row is a char vector, not a number. For example if you type “4”, the variable contains the character 4, which has a numeric value of 52 (ASCII code). Using that to index will create a row #52 and fill it with zeros. To make that row it needed to make the intermediate rows as well, whose values default to 0.
To solve the problem, remove the 's' from the call to input. This will cause the return value to be interpreted as a MATLAB expression, rather than directly returning the entered text as a char vector.
However, if there is a chance that your program is used by a malicious user or a stupid user, this solution is dangerous (as indicated by #Luis Mendo in a comment) because it evaluates whatever the user types, which means the user can e.g. type a command that wipes your hard drive.
A safer solution is to use str2double to convert the char array output of input to a number that you can use to index.

Related

Matlab Histogram Function

I'm new to Matlab and for an assignment my professor is having the class write (complete really) a custom Matlab function for generating a histogram from a set of data. Essentially a new vector is being created, L which is being updated with the information from a 2D matrix M. The first column of L contains the information from M(i,j) and in a second column contains the count (total) of M(i,j) in the data set. I'm in need of some direction as to how to proceed next.
Below is where I'm at thus far:
function L = hist_count(M)
L = [ [0:255' zeros(256,1) ];
for i = 1:size(M,1)
for j = 1:size(M,2)
L(double(M(i,j))+1,2) = <<finish code here>>;
end
end
figure;
plot(L(:1),L(:2));
The <<finish code here>> section is where I'm stuck. I understand everything up to the point where I need to update L with the information.
Assistance is appreciated.
Note: Your initialization of your histogram L has the brackets mismatched.
Remove the second [ bracket in the code. In addition, the creation of the 0:255 vector is incorrect. Doing 0:255' transposes the single constant of 255, which means that it will still create a horizontal vector of 0:255 which will make the code fail. You should surround the creation of this vector with parantheses, then transpose that result. Therefore:
L = [ (0:255)' zeros(256,1) ];
Now onto your actual problem. Judging by your initialization of the histogram, there are 256 possible values so your input is most likely of type uint8, which means that the values in your data will only be from [0-255] in steps of 1. Recall that a histogram records the total number of times you see a value. In this case, you have a two column matrix where the first column tells you the value you want to examine and the second column tells you how many times you see that value in your data. Therefore, each row tells you which value you are examining in your data as well as how many times you have seen that value in your data. Note that the counts are all initialized to zero, so the logic is that every time you see a value, you need to access the right row corresponding to the data point, then increment that value by 1.
Therefore, the line is simply just accessing the current count and adding 1 to it... you then store it back:
L(double(M(i,j))+1,2) = L(double(M(i,j))+1,2) + 1;
M(i,j) is the value found at location (i,j) in your 2D data. The last question you have is why cast the intensity to double and add 1? You cast to double because the input may be an integer type. This means that any values that are beyond the dynamic range of the type will get saturated. Because your input is type uint8, any values beyond 255 will saturate to 255. In MATLAB, we index into rows and columns of a matrix starting at 1 and because the values will potentially start at value 0, this corresponds to row 1 of your histogram so you have to offset by 1. When we get to the most extreme case of value 255 for type uint8 for example, adding 1 to this using the native uint8 will saturate to 255, which means that the values of 254 and 255 get lumped into the same bin. Therefore, you must convert to some type that extends beyond the limits of uint8 and then you add by 1 to avoid saturation. double is usually done here as a default as it has higher precision than uint8, but any type that is higher than uint8 in precision is suitable.

Write to the textbox only if the condition is true in Matlab

I struggle with printing text in my Matlab GUI.
I have code like this in my callback:
if Lia == ismember(handles.T(1:3),(1,1,1))
set(handles.t1, 'String', 'good day');
end
The problem is, I don't know how to check if in my array indexes from 1 to 3 I got this numbers: 1,1,1. I was looking to the documentation but it appears it says nothing about that (or I simply cannot find the proper answer).
You can simply use all and check to see if every element in the first three slots of your array match the values of 1 explicitly. I don't know the shape of your array so I'm going to force it to be a column vector. If the first three slots of the array was a row or column vector and if we assumed that the values of 1 are a column or row vector respectively then you're going to get a rather unpleasant surprise:
h = handles.T(1:3);
if all(h(:) == [1; 1; 1])
set(handles.t1, 'String', 'good day');
end
Note that I could have simply done all(h(:) == 1) as a special case since we are performing a comparison of every element in an array with a single value. However, I have a feeling that this may change for you, so I've decided to explicitly make a vector of 1s so you can change the contents of what you want to compare to at a later time.

changing some values according to a logical index in a specified region of a matrix

I have a matrix and I am interested in changing values that satisfy a certain condition inside that matrix differently, depending on where they are. Say I have a matrix smallPic. How do I obtain a matrix smallPicB with the same dimensions that changed all values that are above 50 in the first two columns to a 255, while those that are in the third and fourth column are changed to a 180?
I have this code which works, but it is pretty ugly and requires splitting the matrix and concatenating it again:
smallPic1=smallPic(:,1:2);smallPic1(smalllPic1>50)=255;
smallPic2=smallPic(:,3:4);smallPic2(smalllPic2>50)=180;
smallPicB = [smalllPic1 smalllPic2];
How would you combine the logical index with the scalar index in one command?
What doesn't work is this:
smallPic(:,smallPic(:,3:4)>50) = 180
Here, the second mention of smallPic inside the brackets does not allow indexing into the correct position of smallPic because it doesn't have the same dimensions as smallPic. So this command actually replaces values in the first two columns of smallPic that are in the same row as those values that are above 50 in the third and fourth column, instead of replacing the values in the third and fourth column themselves.
Any other suggestions?
It probably is not what you're looking for, but it can help if you have lots of assignments like that:
J = repmat(1:size(smallPic, 2), size(smallPic, 1), 1)
smallPic((J<3)&(smallPic>50))=255
smallPic((J>2)&(J<5)&(smallPic>50))=180
You can also call ismember function if column indices are not consecutive:
smallPic(ismember(J, [[1:2 5:6]])&(smallPic>50))=255

MATLAB Extracting Column Number

My goal is to create a random, 20 by 5 array of integers, sort them by increasing order from top to bottom and from left to right, and then calculate the mean in each of the resulting 20 rows. This gives me a 1 by 20 array of the means. I then have to find the column whose mean is closest to 0. Here is my code so far:
RandomArray= randi([-100 100],20,5);
NewArray=reshape(sort(RandomArray(:)),20,5);
MeanArray= mean(transpose(NewArray(:,:)))
X=min(abs(x-0))
How can I store the column number whose mean is closest to 0 into a variable? I'm only about a month into coding so this probably seems like a very simple problem. Thanks
You're almost there. All you need is a find:
RandomArray= randi([-100 100],20,5);
NewArray=reshape(sort(RandomArray(:)),20,5);
% MeanArray= mean(transpose(NewArray(:,:))) %// gives means per row, not column
ColNum = find(abs(mean(NewArray,1))==min(abs(mean(NewArray,1)))); %// gives you the column number of the minimum
MeanColumn = RandomArray(:,ColNum);
find will give you the index of the entry where abs(mean(NewArray)), i.e. the absolute values of the mean per column equals the minimum of that same array, thus the index where the mean of the column is closest to 0.
Note that you don't need your MeanArray, as it transposes (which can be done by NewArray.', and then gives the mean per column, i.e. your old rows. I chucked everything in the find statement.
As suggested in the comment by Matthias W. it's faster to use the second output of min directly instead of a find:
RandomArray= randi([-100 100],20,5);
NewArray=reshape(sort(RandomArray(:)),20,5);
% MeanArray= mean(transpose(NewArray(:,:))) %// gives means per row, not column
[~,ColNum] = min(abs(mean(NewArray,1)));
MeanColumn = RandomArray(:,ColNum);

Copy matrix rows matlab

Lets say i have a matrix A of 300x65. the last column(65th) contains ordered values (1,2,3). the first 102 elements are '1', the second 50 elements are '2' and the remainder will be '3'.
I have another matrix B, which is 3x65 and i want to copy the first row of B by the number of '1's in matrix A. The second row of B should be copied by the number of '2's in in matrix A and the 3th row should be copied by the remaining value of matrix A. By doing this, matrix B should result in a 300x65 matrix.
I've tried to use the repmat function of matlab with no succes, does anyone know how to do this?
There are many inconsistencies in your problem
first if you copy 1 row of B for every element of A(which will end up happening by your description) that will result in a matrix 19500x65
secondly copy its self is a vague term, do you mean duplicate? do you want to store the copied value into a new var?
what I gathered from your problem is you want to preform some operation between A and B to create a matrix and store it in B which in itself will cause the process to warp as it goes if you do not have another variable to store the result in
so i suggest using a third variable c to store the result in and then if you need it to be in b set b = C
also for whatever process you badly described I recommend learning to use a 'for' loop effectively because it seems like that is what you would need to use
syntax for 'for' loop
for i = [start:increment:end]
//loops for the length of [start:increment:end]
//sets i to the nth element of [start:increment:end] where n is the number of times the loop has run
end
If I understand your question, this should do it
index = A(:,end); % will be a column of numbers with values of 1, 2, or 3
newB = B(index,:); % B has 3 rows, which are copied as required by "index"
This should result in newB having the same number of rows as A and the same number of columns as the original B