Initialize variables with names from a file - matlab

I have a txt file with a bunch of parameters created by the external program.
Let us consider a simple example:
input.txt
a= 1
b= 2
c= 3
I can read both names and values in matlab 2018a:
[names, values]=textread('input.txt','%s%f');
As a result, names will be a 3x1 cell array with entries a=, b= and so on, whereas values will be a conventional 3x1 array of doubles.
In my current workspace, I want to initialize the obtained variables (with the corresponding names) and set them equal to the corresponding values.
In the example above, variables a=1, b=2 and c=3 should be created in the current workspace.
I have no idea how to do it...
Thanks!
Edit: in my actual example variable names can contain many characters/numbers (by the standard convention, variable names always start with the letter, not a digit), e.g.
Rcirc1= 30.0
SaveStride= 1000

You can use a combination of regexp and assignin to achieve the desired output:
%Read data.
data = fileread('input.txt')
%Extract variable name and value in named groups.
s = regexp(data,'(?<var>[A-Z]\w+)\D+(?<val>\d+(?:\.\d+)?)','names');
%Loop over struct s contents to create variables in workspace.
cellfun(#(x,y) assignin('base',x,str2double(y)),{s.var},{s.val})

The assignments in the text file can be directly evaluated by MATLAB. You don't need to extract them. In order to silence the text printed for each line you can use evalc
evalc(fileread('input.txt'));

Related

Concatenating Matrices

From what I am understanding about this section,concatenating matrices is when you combine two matrices into one. I have two matrices of the same size, but want to combine them into a third of a different size; I don't understand how or why this would be possible. The sample question I was given in below for reference.
"Given matrices A (75x75) and B (75x75) create matrix C with dimensions (75x150). Assign the number of rows and columns of C to variables named rows and cols using function size."
The following will load variables from the mat file directly into the workspace using the variable names present in the mat file
load('Question4.mat')
Presumably this will load variables A and B into your workspace. This is apparently what is being asked of you.
The following will load variables from the mat file into a single struct variable called C where fieldnames of C will be the variable names from the mat file
C = load('Question4.mat')
This is not what is being asked of you. If you did this you would then have to get at the A and B variables with the syntax C.A and C.B, which isn't what is intended for the assignment.
Assuming you have the variables A and B in the workspace, you can typically concatenate them with the square brackets. Use a comma to concatenate them horizontally, and use a semi-colon to concatenate them vertically. E.g., try these two lines out and see what you get:
[A,B]
[A;B]
Once you have figured out how to get the proper C variable, just use the size( ) function with the two output option (see the section Dimension Lengths as Separate Arguments). See the doc for the size function here:
https://www.mathworks.com/help/matlab/ref/size.html?searchHighlight=size&s_tid=srchtitle

Dynamically labelling in MATLAB

I have a MATLAB script which creates an matrix, 'newmatrix', and exports it as matrix.txt:
save -ascii matrix.txt newmatrix
In my script I also calculate the distance between certain elements of the matrix, as the size of the matrix depends on a variable 'width' which I specify in the script.
width = max(newmatrix(:,5)) - min(newmatrix(:,5))
x_vector = width + 2
And the variable x_vector is defined as width + 2
I want to know is it possible to export x_vector, labelling it as, eg my_vector $x_vector so that "my_vector 7.3" will be produced when the value of x_vector is equal to 7.3
I have tried:
save -ascii 'my_vector' + x_vector
But receive the following errors:
warning: save: no such variable +
warning: no such variable 'my_vector'
Three things:
1) I prefer to use functional form of the calls so that you can pass in variables rather than static strings.
save -ascii matrix.txt newmatrix
is equivalent to:
save('-ascii','matrix.txt','newmatrix')
In other words, in the first form all inputs get treated as string inputs to the function.
2) You can't add character arrays in Matlab. Rather you concatenate them or use sprintf.
name = sprintf('my_vector_%g',x_vector);
save('-ascii',name)
Note by using the functional form we can now pass in a variable. Note however this won't work because name should be either a valid option or a variable, and my_vector_7.3 isn't either.
3) I'm not entirely sure what you're asking, but I think you want the text file to say "my_vector 7.3". I don't think -ascii supports strings .... You could write something using fprintf.
fid = fopen('matrix.txt','w');
fprintf(fid,mat2str(new_matrix));
fprintf(fid,'\n');
fprintf(fid,'my_vector %g',x_vector);
fclose(fid);

Performing operations on a variable number of workspace elements in MATLAB

new MATLAB user here so apologies if this seems like a silly question. I have the following list of variables (doubles) in my workspace:
E1_01Strain E1_06Strain E1_07Strain E1_08Strain E1_09Strain E1_10Strain
E1_01Stress E1_06Stress E1_07Stress E1_08Stress E1_09Stress E1_10Stress
These are lists of numbers. I would like to remove the last n elements from each variable. I can do it with the command
E1_01Strain = E1_01Strain(1:end-100)
but it's impractical because later I'm going to have to do it on many, many more similar variables. Therefore I wanted to write a function that accepts as inputs a list of the workspace variables (as in, I highlight the variables I want and drag and drop into the function input) and removes from each one n elements.
I understand that I can write a function like this:
function [X1, X2, X3, X4] = Remove_n_elements[n, X1, X2, X3, X4]
X1 = X1(1:end-100);
X2 = X2(1:end-100);
X3 = X3(1:end-100);
X4= X4(1:end-100);
end
but that would mean that I would have to change the number of inputs, outputs, and the lines of code in the function every time. I'm sure there's a better way to do it but I can't figure it out.
I keep thinking that there might be a way to do it by looping over all the inputs but I can't get it to work since (as far as I know) I need to create a list of the inputs and then the operation is performed only on the elements of that list, not the inputs themselves.
I was looking at Passing A Variable Number of Arguments into a Function and from that using inputParser from https://www.mathworks.com/help/matlab/matlab_prog/parse-function-inputs.html but since I'm new to MATLAB I'm not sure how to use it for my case.
I used the code provided by il_raffa for a bit but followed his advice and went back and reconsidered how the script functions. After some more digging I wrote the following script that does exactly what I need. This script extracts the columns des_cols from all .csv files in a folder and plots them together. It then makes another plot of the averages.
files = dir('*.csv'); % navigate to the folder that you want to run the script on in MATLAB
avgStress = [];
avgStrain = [];
set(groot, 'DefaultLegendInterpreter', 'none') % the names of my .csv files have underscores that I want to see in the legend, if you don't want this then comment this line
hold on; %comment this and hold off further down if you want separate plots for every .csv
for file = files'
csv = xlsread(file.name);
[n,s,r] = xlsread(file.name);
des_cols = {'Stress','Ext.1(Strain)'}; % type here the names of the columns you want to extract
colhdrs = s(2,:);
[~,ia] = intersect(colhdrs, des_cols);
colnrs = flipud(ia);
file.name = n(:, colnrs);
file.name = file.name(1:end-600,:); % I wanted to remove the last 600 rows but if you want them all, remove the -600
plot(file.name(:,2),file.name(:,1),'DisplayName',s{1,1});
avgStress = [avgStress file.name(1:1500,1)]; % calculates the average stress for the first 1500 points, you can change it to whatever you want
avgStrain = [avgStrain file.name(1:1500,2)];
end
ylabel({'Stress (MPa)'}); % y-axis label
xlabel({'Strain (%)'}); %x-axis label
title({'E_2'}); % title of the plot
legend('show');
hold off; % commment this if you want different plots for all .csv files
avgStress = mean(avgStress,2);
avgStrain = mean(avgStrain,2);
plot(avgStrain,avgStress);
This creates two plots, one with all the raw data and another with just the averages. I hope this helps anyone that might have a similar issue.
The best thing you can do is to review the architecture of your SW in order to avoid the needs to perform such operations on the Workspace variables.
That is: how those variables are created? Are these variables loaded from a ".mat" file? etc.
Anyway, in order to avoid using the eval function and given your situation, a possible approach could be:
identify the names of the varailbes by using the function who. You can specify in the call to who the root name of the varaibles and use the * as, for example, who('E1*'). Make sure it fit wiht the desired variables. You can also use regexp to better refine the selection of the variables
save these varaibles in a temporary .mat file: the name (including the path of the temporary file can be created with the function tempname
load the temporary .mat file: this will create a struct in the Workspace whose fields are the variables you want to midify
call the function to remove the undesired elements form the fields of the struct. The function have to return the updated struct
save the updated struct in the temporary file
load again the temporary file by specifying the option -struct which allows loading the content of the file as single varaibles
The function to remove the undesired elements can be made as follows:
get the nams of the struct's fields by using the function fieldnames
loop over the filed of the struct by using the dynamic field names property
remove the undesired elements form the fields
return the updated struct
A possible implementatin could be:
Code "before" the call to the function
% Get the names of the variables
list_var=who('E1*')
% Define the name of a temporary ".mat" file
tmp_file=tempname
% Save the variables in the temporary ".mat" file
save(tmp_file,list_var{:});
% Load the variables in a struct
sel_vars=load(tmp_file);
% Call the function to remove the elements
out_str=Remove_n_elements(8,sel_vars)
Function to remove the undesired elements
function sel_vars=Remove_n_elements(n,sel_vars)
% Get the names of the fields of the struct
var_names=fieldnames(sel_vars)
% Loop over the fields and remove the undesired elements
for i=1:length(var_names)
sel_vars.(var_names{i})=sel_vars.(var_names{i})(1:end-n)
end
Code "after" the call to the function
% Save the updated struct in the temporary ".mat" file
save(tmp_file,'-struct','out_str')
% Load the updated struct as separate variables
load(tmp_file)

How to rename table variables in Matlab?

I would like to create a table from a matrix of spectra data, using a specific list of variables (column, which here correspond to 1000 spectral wavelenght values) instead of putting the name manually.
To do so, i use the array2table function, and matlab documentation shows that names for rows and label of variables must be put as cell arrays, (and not matrix). So I need to first convert my x-axis (spectral wavelenght) to a cell array. I use the following:
C = num2cell(xaxis); % to convert into a cell array (each cell contain 1 value)
isvarname C % to check that the variable is valid as a cell array
T = array2table(R,'RowNames', concentration,'VariableNames',C);
Here: R is the matrix, concentration is a Cell array 1x500, xaxis is the wavelenght of spectral data 1x1000 (which is ranged from 600 to 1800, approx. there is no null value).
Unfortunately, I got the following error:
"Error using array2table (line 62)
The VariableNames property must be a cell array, with each element containing one nonempty string."
which means I can input properly the columns (variable) names (while row names, however, works fine).
Note: i tried the
T.Properties.VariableNames = c but it is not working either.
I checked the other post on table name value but its not helping,
Any thought about this?
Thank you very much.
Maybe you mistyped your question's code, but it seems that you are using the array xaxis instead of C. Anyway, I suggest you try casting the cells content to strings this way
T = array2table(R,'RowNames', concentration,'VariableNames',cellfun(#(x)num2str(x),num2cell(xaxis),'uniformoutput',false));
Edit
Looking through the table docs it says that
Variable names, specified as the comma-separated pair consisting of 'VariableNames' and a cell array of character vectors that are nonempty and distinct. The number of character vectors must equal the number of variables. The variable names that you assign must be valid MATLABĀ® variable names. You can determine valid variable names using the function isvarname.
Furthermore, the isvarname function says that
A valid variable name begins with a letter and contains not more than namelengthmax characters. Valid variable names can include letters, digits, and underscores. MATLAB keywords are not valid variable names. To determine if the input is a MATLAB keyword, use the iskeyword function.
This means that you cannot use the xaxis values as variable names by themselves, you need to, at least, prepend a character and remove the decimal dot. You can do so with the following
T = array2table(R,'RowNames', concentration,...
'VariableNames',cellfun(#(x)['wavel_',regexprep(num2str(x),'.','_')],num2cell(xaxis),'uniformoutput',false));
This code will prepend 'wavel_' to the numerical string value. It will also replace the dots with underscores using the regexprep function. However, it seems like this is really unnecessary because the column names are not really informative. The array2table function's doc says that if you don't supply the 'variableNames' option it will do the following:
If valid MATLAB identifiers are not available for use as variable names, MATLAB uses a cell array of N character vectors of the form {'Var1' ... 'VarN'} where N is the number of variables.
Maybe using the default variable names is good enough.

How to share variables between different m files in Matlab

I have three m files using the same variables and carrying out calculations on these variables. I have made an index m file in which i have declared all the variables and I can share the variables to the remaining m files using the variable names. My problem is that the variable names change too often and then I have to change the variable names in all these files manually. How can I make a Matlab script which can automatically get the variable names and value from the index m file and put these to the remaining m files.
I feel like you just need a little example from where you could go on so here we go:
First calling each value with a different variable name. if you have a lot of values of the same type a array is easier like:
A0=0; A1=6; A2=12 %each one with its own name
B=zeros(16,1); %create an array of 16 numbers
B(1)= 0; %1 is the first element of an array so care for A0
B(2)= 6;
B(8)= 12;
disp(B); % a lot of numbers and you can each address individually
disp(B(8)); %-> 12
you can put all that in your script and try it. Now to the function part. Your function can have input, output, neither or both. If you just want to create data you wont need an input but an output.
save this as myfile1.m:
function output = myfile1()
number=[3;5;6]; %same as number(1)=3;number(2)=5;number(3)=6
%all the names just stay in this function and the variable name is chosen in the script
output = number; %output is what the file will be
end
and this as myfile2.m
function output = myfile2(input)
input=input*2;%double all the numbers
%This will make an error if "input" is not an array with at least 3
%elements
input(3)=input(3)+2; %only input(3) + 2;
output = input;
end
and now try
B=myfile1() %B will become the output of myfile1
C=myfile2(B) %B is the input of myfile2 and C will become the output
save('exp.mat','C')
I hope this will get you started.