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

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

Related

Trouble calling columns from an excel file

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);

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.

Evaluate a variable from a function and assign the new variable into base Workspace

I have a GUI that takes users typed-in equations such as delta_P=C1-C2;velocity=diff(y)./diff(x); all in one string delimited and terminated by ;. Then, within the GUI function, I pull in C1, C2, x, and y in and I want to evaluate to generate delta_P and velocity and assign them into the base Workspace. My problem is I don't know delta_P and velocity ahead of time so that I can't just do:
assignin('base','delta_P',C1-C2);
I need to break down the string to identify the new variable names left of the equal signs and assign to them what are right of the equal signs into the base Workspace?
I condition an input string with one or more statements so that there is no space and no carriage return. Then, I tried the following:
str_in = 'delta_P=C1-C2;velocity=diff(y)./diff(x);'
str_sp = strsplit(str_in,';');
str_sp = str_sp(1:end-1); % last ';' results in an empty char
Then, this is where I get lost:
cellfun(#(c1,c2)assignin('base',c1(1:c2-1),c1(c2+1:end)),str_sp,cellfun(#(c)strfind(c,'='),str_sp,'uni',0),'uni',0);
It just doesn't look efficient
It still doesn't work as c1(c2+1:end) is also a string
I tried eval(c1(1:c2-1)), but MATLAB complains C1,C2,x, and y are undefined.
Thanks.
You should evaluate the expression in the current workspace, and then evaluate the assignment in the base workspace.
Here's an example function which illustrates the logic:
function q61401249
C1 = 1;
C2 = 2;
x = [1 1 2];
y = [2 3 4];
str_in = 'delta_P=C1-C2;velocity=diff(y)./diff(x);';
str_sp = strsplit(str_in,';');
str_sp = str_sp(1:end-1);
for i = 1:length(str_sp)
s = split(str_sp(i),'=');
assignin('base',s{1},eval(s{2}));
end
end
when you run the function, you will see that two new variables have been created in the base workspace, delta_P and velocity as desired.
Of course the assumption here is that the equation is well formed, for instance that there aren't two = signs.

Run time series analysis for multiple series Matlab

I wish to apply the same data analysis to multiple data time series. However the number of data series is variable. So instead of hard-coding each series' analysis I would like to be able to specify the number and name of the funds and then have the same data-manipulation done to all before they are combined into a single portfolio.
Specifically I have an exel file where each worksheet is a time series where the first column is dates and the second column is prices. The dates for all funds may not correspond so the individual worksheets must be sifted for dates that occur in all the funds before combining into one data set where there is one column of dates and all other columns correspond to the data of each of the present funds.
This combined data set is then analysed for means and variances etc.
I currently have worked out how to carry out the merging and the analysis (below) but I would like to know how I can simply add or remove funds (i.e. by including new worksheets containing individual funds data in the excel file) without having to re-write and add/ remove extra/excess matlab code.
*% LOAD DATA*
XL='XLData.xlsx';
formatIn = 'dd/mm/yyyy';
formatOut = 'mmm-dd-yyyy';
*%SPECIFY WORKSHEETS*
Fund1Prices=3;
Fund2Prices=4;
*%RETRIEVE VALUES*
[Fund1values, ~, Fund1sheet] = xlsread(XL,Fund1Prices);
[Fund2values, ~, Fund2sheet] = xlsread(XL,Fund2Prices);
*%EXTRACT DATES AND DATA AND COMBINE (TO REMOVE UNNECCESSARY TEXT IN ROWS 1
%TO 4) FOR FUND 1.*
Fund1_dates_data=Fund1sheet(4:end,1:2);
Fund1Dates= cellstr(datestr(datevec(Fund1_dates_data(:,1),formatIn),formatOut));
Fund1Data= cell2mat(Fund1_dates_data(:,2));
*%EXTRACT DATES AND DATA AND COMBINE (TO REMOVE UNNECCESSARY TEXT IN ROWS 1
%TO 4) FOR FUND 2.*
Fund2_dates_data=Fund2sheet(4:end,1:2);
Fund2Dates= cellstr(datestr(datevec(Fund2_dates_data(:,1),formatIn),formatOut));
Fund2Data= cell2mat(Fund2_dates_data(:,2));
*%CREATE TIME SERIES FOR EACH FUND*
Fund1ts=fints(Fund1Dates,Fund1Data,'Fund1');
Fund2ts=fints(Fund2Dates,Fund2Data,'Fund2');
*%CREATE PORTFOLIO*
Port=merge(Fund1ts,Fund2ts,'DateSetMethod','Intersection');
*%ANALYSE PORTFOLIO*
Returns=tick2ret(Port);
q = Portfolio;
q = q.estimateAssetMoments(Port)
[qassetmean, qassetcovar] = q.getAssetMoments
Based on edit to the question, the answer was rewritten
You can put your code into a function. This function can be saved as an .m-file and called from Matlab.
However, you want to replace the calls to specific worksheets (Fund1Prices=3) with an automated way of figuring out how many worksheets there are. Here's one way of how to do that in a function:
function [Returns,q,qassetmean,qassetcovar] = my_data_series_analysis(XL)
% All input this function requires is a variable
% containing the name of the xls-file you want to process
formatIn = 'dd/mm/yyyy';
formatOut = 'mmm-dd-yyyy';
% Determine the number of worksheets in the xls-file:
[~,my_sheets] = xlsfinfo(XL);
% Loop through the number of sheets
% (change the start value if the first sheets do not contain data):
% this is needed to merge your portfolio
% in case you do not start the for-loop at I=1
merge_count = 1;
for I=1:size(my_sheets,2)
% RETRIEVE VALUES
% note that Fund1Prices has been replaced with the loop-iterable, I
[FundValues, ~, FundSheet] = xlsread(XL,I);
% EXTRACT DATES AND DATA AND COMBINE
% (TO REMOVE UNNECCESSARY TEXT IN ROWS 1 TO 4)
Fund_dates_data = FundSheet(4:end,1:2);
FundDates = cellstr(datestr(datevec(Fund_dates_data(:,1),...
formatIn),formatOut));
FundData = cell2mat(Fund_dates_data(:,2));
% CREATE TIME SERIES FOR EACH FUND
Fundts{I}=fints(FundDates,FundData,['Fund',num2str(I)]);
if merge_count == 2
Port = merge(Fundts{I-1},Fundts{I},'DateSetMethod','Intersection');
end
if merge_count > 2
Port = merge(Port,Fundts{I},'DateSetMethod','Intersection');
end
merge_count = merge_count + 1;
end
% ANALYSE PORTFOLIO
Returns=tick2ret(Port);
q = Portfolio;
q = q.estimateAssetMoments(Port)
[qassetmean, qassetcovar] = q.getAssetMoments
This function will return the Returns, q, qassetmean and qassetcovar variables for all the worksheets in the xls-file you want to process. The variable XL should be specified like this:
XL = 'my_file.xls';
You can also loop over more than one xls-file. Like this:
% use a cell so that the file names can be of different length:
XL = {'my_file.xls'; 'my_file2.xls'}
for F=1:size(XL,1)
[Returns{F},q{F},qassetmean{F},qassetcovar{F}] = my_data_series_analysis(XL{F,1});
end
Make sure to store the values which are returned from the function in cells (as shown) or structs (not shown) to account for the fact that there may be a different number of sheets per file.

Plotting multiple lines within a FOR loopin MATLAB

Okay so this sounds easy but no matter how many times I have tried I still cannot get it to plot correctly. I need only 3 lines on the same graph however still have an issue with it.
iO = 2.0e-6;
k = 1.38e-23;
q = 1.602e-19;
for temp_f = [75 100 125]
T = ((5/9)*temp_f-32)+273.15;
vd = -1.0:0.01:0.6;
Id = iO*(exp((q*vd)/(k*T))-1);
plot(vd,Id,'r',vd,Id,'y',vd,Id,'g');
legend('amps at 75 F', 'amps at 100 F','amps at 125 F');
end;
ylabel('Amps');
xlabel('Volts');
title('Current through diode');
Now I know the plot function that is currently in their isn't working and that some kind of variable needs setup like (vd,Id1,'r',vd,Id2,'y',vd,Id3,'g'); however I really can't grasp the concept of changing it and am seeking help.
You can use the "hold on" function to make it so each plot command plots on the same window as the last.
It would be better to skip the for loop and just do this all in one step though.
iO = 2.0e-6;
k = 1.38e-23;
q = 1.602e-19;
temp_f = [75 100 125];
T = ((5/9)*temp_f-32)+273.15;
vd = -1.0:0.01:0.6;
% Convert this 1xlength(vd) vector to a 3xlength(vd) vector by copying it down two rows.
vd = repmat(vd,3,1);
% Convert this 1x3 array to a 3x1 array.
T=T';
% and then copy it accross to length(vd) so each row is all the same value from the original T
T=repmat(T,1,length(vd));
%Now we can calculate Id all at once.
Id = iO*(exp((q*vd)./(k*T))-1);
%Then plot each row of the Id matrix as a seperate line. Id(1,:) means 1st row, all columns.
plot(vd,Id(1,:),'r',vd,Id(2,:),'y',vd,Id(3,:),'g');
ylabel('Amps');
xlabel('Volts');
title('Current through diode');
And that should get what you want.