Trouble calling columns from an excel file - matlab

I am trying to call an excel file and run it into my function to output an array of calculated velocities given time, angle, and radius in MATLAB
This is my code so far:
function [vR,vTheta,v] = temp_func(time,radius,theta)
vR = (radius(2:1:end) - radius(1:1:end-1))./((time(2:1:end) - time(1:1:end-1)))
vTheta = (theta(2:1:end)*(pi./180) - theta(1:1:end-1)*(pi./180))./((time(2:1:end) - time(1:1:end-1)))
v = ((vR(1:1:end)).^2.+(vTheta(1:1:end)).^2).^(1/2)
end
This code works if I were to call something like temp_func([0 1 2], [0 1 3], [0 0 180]).
However, I need to call the columns in a 1083x3 excel file (called GPSdata) and I am unsure how directly call for this matrix. I've tried temp_func(GPSdata(1:end,1),GPSdata(1:end,2),GPSdata(1:end,3))
To call the first, second, and third columns respectively. But I get this error:
Error using ()
Subscripting into a table using one subscript (as in t(i)) is not supported. Specify a row subscript and a variable
subscript, as in t(rows,vars). To select variables, use t(:,i) or for one variable t.(i). To select rows, use t(i,:).

The error message you're seeing suggests that GPSdata might be a table instead of a matrix. If it is a table, you can use table variables to access the columns instead of matrix indices.
GPSdata = readtable('excel.xlsx');
time = GPSdata.Time;
radius = GPSdata.Radius;
theta = GPSdata.Theta;
[vR, vTheta, v] = temp_func(time, radius, theta);
Assuming ofcours that the column headers in your Excel file are "Time", "Radius", and "Theta", you can use these names to access the corresponding columns in the table.
Alternatively, you can convert the table to a matrix using the table2array function, GPSmatrix = table2array(GPSdata); and then access the columns using matrix indices.
time = GPSmatrix(:, 1);
radius = GPSmatrix(:, 2);
theta = GPSmatrix(:, 3);

Related

save columns of matrix in vector variables in Matlab

In Matlab (R2021b) I am using some given function, which reads time-dependent values of several variables and returns them in a combined matrix together with a time vector. In the data matrix each column represents one vector of time-dependent values for one variable.
[data,time] = function_reading_data_of_several_values('filename');
For readability of the following code where the variables are further processed, I would like to store these columns in separate vector variables. I am doing it like that:
MomentX = data(1,:);
MomentY = data(2,:);
MomentZ = data(3,:);
ForceX = data(4,:);
ForceY = data(5,:);
ForceZ = data(6,:);
That is working. But is there some simpler (or shorter) way of assigning the column of the matrix to individual vectors? I am asking because in real program I have more than the 6 columns as in the example. Code is getting quite long. I was thinking of something similar to the line below, but that does not work:
[MomentX,MomentY,MomentZ,ForceX,ForceY,ForceZ] = data; %does not work
Do you have any idea? Thanks for help!
Update:
Thanks to the hint here in the group to use tables, a solution could be like this:
...
[data,time] = function_reading_data_of_several_values('filename');
% data in matrix. Each column representing a stime dependent variable
varNames = {'MomentX', 'MomentX',...}; % Names of columns
T=array2table(data','VariableNames',varNames); % Transform to Table
Stress = T.MomentX/W + T.ForceY/A %accesing table columns
...
This seems to work fine and readable to me.
Solution 1: In industrial solutions like dSpace, it is very common to do it in struct arrays:
mydata.X(1).time = [0.01 0.02 0.03 0.04];
mydata.Y(1).name = 'MomentX';
mydata.Y(1).data = [1 2 3 4];
mydata.Y(2).name = 'MomentY';
mydata.Y(2).data = [2 3 4 5];
Solution 2: It is also very common to create tables
See: https://de.mathworks.com/help/matlab/ref/table.html
As already commented, it is probably better to use a table instead of separate variables may not be a good idea. But if you want to, it can be done this way:
A = magic(6): % example 6-column matrix
A_cell = num2cell(A, 1); % separate columns in cells
[MomentX, MomentY, MomentZ, ForceX, ForceY, ForceZ] = A_cell{:};
This is almost the same as your
[MomentX,MomentY,MomentZ,ForceX,ForceY,ForceZ] = data; %does not work
except that the right-hand side needs to be a comma-separated list, which in this case is obtained from a cell array.

Extract and combine different values from table and make new variables (for histogram)

I have a 4x15 table (4 participants and 15 variables). I want to make histograms (or plots)for all the participants individually.
For one variable (x-axis), I want to combine three values that are not individual variables (3 of the 15), they are all Reaction times from different trials.
For the other variable (y-axis), I also want to combine what in the table now are three different variables into one variable with three expressions (values).
So the question is how I can extract 3 cells values (say from the first row for the first participants), and combine them into 3 values of one variable. And then do the same for the other variable, which i want to plot in the last step.
I tried the following already (but does not seem to work):
LNBtableS1 is the name of the 4x15 table
LNB_TP0, LNB_TP1, etc are the variable names
%assign values from cells (same row) to new variable (one variable with different expressions/values
%how to extract specific values from table and combine them into new variable with three expression /datapoints?
x = (1:1,[LNB_TP0 LNB_TP1 LNB_TP2])% first row = first participant
x1 = LNBtableS1.LNB_TP0 (1:1,[LNB_TP0])
x2 = LNBtableS1.LNB_TP1 (1:1,[LNB_TP1])
x3 = LNBtableS1.LNB_TP2 (1:1,[LNB_TP2])
y= (1:1,[LNB_RTC0 LNB_RCT1 LNB_RCT2])
y1 = LNBtableS1.LNB_RTC0 (1:1,[LNB_RTC0])
y2 = LNBtableS1.LNB_RTC1 (1:1,[LNB_RTC1])
y3 = LNBtableS1.LNB_RTC2 (1:1,[LNB_RTC2])
%plot or make histogram from x and y
I also tried this to make a new table with two variables and the corresponding values, which also does not seem to work
TG = newtable([LNB_TP0; LNB_TP1; LNB_TP2],[LNB_RTC0;LNB_RTC1;LNB_RTC2],
'VariableNames',{'TP','RT'})
TG = newtable([LNBtableS1(1:1, {'LNB_TP0', 'LNB_TP1', 'LNB_TP2'})],[LNBtableS1(1:1, {'LNB_RTC0', 'LNB_RTC1', 'LNB_RTC2'})],
'VariableNames',{'TP','RT'})
TG = newtable([LNBtableS1(1:1,[19 22 25])],[LNBtableS1(1:1,[21 24 27])], 'VariableNames',{'TP','RT'})
Neither does it work to create new variables like this (which I can then combine in a plot or histo):
Try with dataset
%create new variable with cells values from table
TP = LNBtableS1(1:1, {'LNB_TP0', 'LNB_TP1', 'LNB_TP2'})
RT = LNBtableS1(1:1, {'LNB_RTC0', 'LNB_RTC1', 'LNB_RTC2'})
%create indexing? -> doesn't work
TP = LNBtableS1(1:1, {'LNB_TP0' 1; 'LNB_TP1' 2; 'LNB_TP2' 3});
RT = LNBtableS1(1:1, {'LNB_RTC0' 1; 'LNB_RTC1' 2; 'LNB_RTC2' 3})
%make into dataset

How to gather results with parfor in MATLAB

I have a function called SpreadFinder which returns an array of structures:
[ spreads ] = SpreadFinder( pp, corr_thres, i_range )
The return object looks like this:
spreads =
1x4026 struct array with fields:
px
tuple
beta
The code is:
m = containers.Map(0, 0, 'uniformValues',false); m.remove(0);
parfor col = 1:8
spreads = SpreadFinder(pp, 0.8, i_ranges(:,col)');
m(col) = spreads;
end
When I run it, I have this error:
Subscripted assignment dimension mismatch.
I know the Map can be used to store an array of structures. (https://stackoverflow.com/a/2365526)
This code below works. So I don't think it's a problem of dimension...
m(1) = spreads(1:2);
m(2) = spreads(1:4);
The objective is to merge all the results into one map and possibly iterate over this map after the parallel task.
Can someone help me out?
Best,
IIRC, you cannot assign to a containers.Map inside a parfor because a containers.Map is not sliceable. If you want to assign elements to an array inside a parfor, it must be sliceable. What I mean by sliceable is that you are able to extract a subset of the values via the colon operator (i.e. 1:3, 2:4), etc. You cannot do that with a containers.Map unless you specifically use the values function, and from there you can specify a cell array of keys and get the values from there. Using () syntax only permits you to access one key at a time.
Therefore, what I would suggest you do is assign the outputs to a cell array, and use this cell array as values into your containers.Map. Something like this:
%// Create temporary cell array of values
c = cell(1,8);
%// Run parfor for each col
parfor col = 1:8
c{col} = SpreadFinder(pp, 0.8, i_ranges(:,col)');
end
%// Make a new containers.Map for these values
m = containers.Map(1:8, c, 'uniformvalues', false);
%clear c; %// Optional if you don't want the temporary cell array to stick around

MATLAB QUESTIONS on logical indexing and cell2struct function

First Question:
Hello there!
I am trying to assign this vector
v(mod(v,2)~=0)=0
The operations is supposed to replace odd numbers in a vector with 0. I am trying to assign this vector to result variable in a function.
something goes wrong when I try this
function
function [result1,result2] = myfunction(v)
v(mod(v,2)==0)= 0;
result1 = v;
v(mod(v,2)~=0) = 0;
result2 = v;
return
QUESTION 2:
I am trying to figure out an alternative way to express the the function cell2struct in for-loop format
for example,
if we have a cell array with 2 dimensions containing food labels. Their names, caloric count and price, each in one column. Can we write a function that's can transfer the information in cells to a struct that contain each of the fields above?
Thanks
Question #1
You are setting all even numbers to 0, but then you are using this mutated result to search for odd numbers and setting them to 0. This will probably not give you what you intended as you are using a modified copy of the original vector, so it would be prudent that you keep a copy of the vector before doing each operation.
function [result1,result2] = myfunction(v)
vcopy = v; %// Make a copy
vcopy(mod(vcopy,2)==0)= 0; %// Find even numbers and set to 0
result1 = vcopy;
vcopy = v; %// Make another copy
vcopy(mod(vcopy,2)~=0) = 0; %// Find odd numbers and set them to 0.
result2 = vcopy;
return
Question #2
Yup. If you have a list of field names stored in f and their corresponding entities for each field stored in c, simply use a loop like so:
function [s] = my_cell2struct(c, f)
for idx = 1 : numel(f)
s.(f{idx}) = c{idx};
end
The above code does no error checking, so you need to make sure that the total number of elements in c matches those of f. Also, c and f must be cell arrays. Notice that s wasn't declared at all in the function. Also, using the dot operator combined with enclosing brackets and a string that goes inside the enclosing brackets allows you to dynamically create field names on the fly. As such, for each string in f, we access the corresponding value stored in c, and we create a field name that contains this value.
Here's a reproducible example from the MathWorks documentation:
c = {'tree',37.4,'birch'};
f = {'category','height','name'};
s = cell2struct(c, f, 2)
s =
category: 'tree'
height: 37.4000
name: 'birch'
Notice that I use cell2struct here from native MATLAB to produce the above structure. Doing the above for loop which is wrapped in a function called my_cell2struct, we get:
c = {'tree',37.4,'birch'};
f = {'category','height','name'};
s = my_cell2struct(c, f)
s =
category: 'tree'
height: 37.4000
name: 'birch'

MATLAB convert from struct to table and ouput as csv

As part of an image processing pipeline using 'regionprops' in Matlab I generate the struct:
vWFfeatures =
1631x1 struct array with fields:
Area
Centroid
MajorAxisLength
MinorAxisLength
Eccentricity
EquivDiameter
Where 'Centroid' is a Vector containing [x, y] for example [12.4, 26.2]. I would like to convert this struct to a table and save as a CSV file. The objective is to separate the 'Centroid' vector into two columns in the table labelled Centroid_X and Centroid_Y for example. I am not sure how to achieve this.
So far I have investigated using the 'struct2table' function. This ouputs the 'Centroid' as one column. In addition when I try to assign the output to a variable I get an error:
table = struct2table(vWFfeatures)
Error using struct2table
Too many output arguments.
I cannot understand this, any help please?
Since the original struct2table isn't available to you, you might want to implement specifically the behavior you're trying to achieve yourself.
In this case, this means extracting the values you want to save, (split the array,) then save the data:
data_Centroid = vertcat(vWFfeatures.Centroid); %// contains the centroid data
Centroid_X = data_Centroid(:,1); %// The first column is X
Centroid_Y = data_Centroid(:,2); %// the second column is Y
csvwrite('centroid.csv',data_Centroid); %// writes values into csv
If you want column headers in your csv, it gets complicated because csvwrite can only handle numeric arrays:
celldata = num2cell(num2str(data_Centroid)); %// create cell array
celldata(:,3) = celldata(:,4); %// copy col 4 (y data) into col 3 (spaces)
for i=1:length(celldata)
celldata{i,2} = ','; %// col 2 has commas
celldata{i,4} = '\n'; %// col 4 has newlines
end
celldata = celldata'; %'// transpose to make the entries come columnwise
strdata = ['Centroid_X,Centroid_Y\n',celldata{:}]; %// contains all as string
fid = fopen('centroid.csv','w'); % writing the string into the csv
fprintf(fid,strdata);
fclose(fid);
This is how I solved it in the end: extracted each field from struct used horzcat to join into a new array then defined headers and used csvwrite_with_headers, to ouput to csv.
wpbFeatures = regionprops(vWFlabelled, 'Area','Centroid', 'MajorAxisLength', 'MinorAxisLength', 'Eccentricity', 'EquivDiameter');
wpbArea = vertcat(wpbFeatures.Area);
wpbCentroid = vertcat(wpbFeatures.Centroid);
wpbCentroidX = wpbCentroid(:,1);
wpbCentroidY = wpbCentroid(:,2);
wpbFeret = max(imFeretDiameter(vWFlabelled, linspace(0,180,201)), [], 2);
wpbMajorAxisLength = vertcat(wpbFeatures.MajorAxisLength);
wpbMinorAxisLength = vertcat(wpbFeatures.MinorAxisLength);
wpbEccentricity = vertcat(wpbFeatures.Eccentricity);
wpbEquivDiameter = vertcat(wpbFeatures.EquivDiameter);
wpbFeatures = horzcat(wpbArea, wpbCentroidX, wpbCentroidY, wpbFeret, wpbMajorAxisLength, wpbMinorAxisLength, wpbEccentricity, wpbEquivDiameter);
headers = {'Area','CentroidX','CentroidY', 'Feret', 'MajorAxisLength', 'MinorAxisLength', 'Eccentricity', 'EquivDiameter'};
csvwrite_with_headers(strcat(PlateName, '_ResultsFeatures.csv'),wpbFeatures,headers);