How to convert string to variable name which will be passed into plot function - matlab

How I can convert a string to a variable which will be passed into plot function?
Time = [0,1,2,3];
A = sin(Time);
B = cos(Time);
c = 2*sin(Time);
lookup = {"A", "Freq(Hz)"; "B", "Pressure(bar)", "c", "time(ms),....};
for i=1:length(lookup)
plot(Time, lookup(i,1))
ylabel(lookup(i,2))
end
I want to plot Time vs A and Time vs B and Time vs C likewise I have 50 different variables to plot.
So I planned to create the lookup with string and planned to pass as variable to plot function using eval function call.
But in few places I read that using eval is not good option so kindly suggest the alternate method.

This will solve your immediate problem:
Replace
lookup = {"A", "Freq(Hz)"; "B", "Pressure(bar)", "c", "time(ms)", ...};
with
lookup = {A, "Freq(Hz)"; B, "Pressure(bar)", c, "time(ms)", ...};
Cell arrays are heterogeneous containers, each element can be an array of any time, independently from all other types.
With this change, the rest of your code should work as intended. You might want to add a figure command or a print command inside your loop, as each plot will overwrite the previous one. figure creates a new figure window to plot in, you'll have 50 windows (not so nice). print can save the plot to a file, which might be a better approach here. Don't try to combine the 50 data lines into a single plot, it'll be a mess!
On a larger scale, you might want to rethink your strategy with defining 50 different variables. Cell arrays and struct arrays are really good ways to go about this. For example, you can think of
data.A = sin(Time);
data.B = cos(Time);
data.c = 2*sin(Time);
or
data(1).values = sin(Time);
data(1).name = "A";
data(1).units = "Freq(Hz)";
data(2).values = cos(Time);
data(2).name = "B";
data(2).units = "Pressure(bar)";
data(3).values = 2*sin(Time);
data(3).name = "c";
data(3).units = "time(ms)";
Note that, in the first case, you can also index with data.("A"), which brings you pretty close to your original idea, except that you don't have 50 variables in your workspace, but one single data structure that is easier to deal with.
Here is a very detailed list of reasons why eval can be bad to use. That link also shows some alternatives, similar to what I summarized above.

Related

How to create a new matrix with a for loop in MATLAB?

I am a newbie. I have problem.
I have 20 (1x100) different named vectors. I want to combine these vectors to create a 20x100 matrix with a for loop.
There are the examples of vectors.
namelist=["First","B","New"]
First = [1:100]
B = [1:2:200]
New = [4:4:400]
for i = 1: length(namelist)
new_database(i,1:end) = namelist{i}
end
But, when I want to try this I saw "The end operator must be used within an array index expression." error.
I know I can do same thing with this:
"new_database= [First;B;New]"
but i want to do this with a for loop.
Would you help me how can fix this error? or Would you explain me how can do this?
Your problem is with this line:
new_database(i,1:end) = namelist{i}
the curly braces are used with cells, exclusively and there is no need to use range indexing as you do (i, 1:end)
Generally, it is better practice to assign character arrays or strings to cells.
One question, what are you doing with the 'First', 'New' and 'B' ranges arrays?
Something like:
namelist=["First","B","New"]
First = [1:100];
B = [1:2:200];
New = [4:4:400];
new_database = cell(1, length(namelist));
for i = 1: length(namelist) % or length(new_database)
new_database{i} = namelist(i)
end
which generates this output:
EDIT: My apologies, now I see what you are trying to accomplish. You are building a database from a series of arrays, correct?
Following my previous response, you must consider some points:
1 Your new_database should be square. Regardless of the dimensions of the arrays you are passing to it, if you form a cell from them, you will invariably have empty cells if no data is passed to those rows or columns
2 In some cases, you don't need to use for-loops, where simple indexing might suffice your case problem. Consider the following example using cellstr:
titles = ["Position", "Fruits", "Mythical creatures"]
A = ["One", "Two", "Three"];
B = ["Apple", "Banana", "Durian"];
C = ["Dragon", "Cat", "Hamster"];
db = cell(4, 3);
db(1,:) = cellstr(titles)
db(2:end,1) = cellstr(A)
db(2:end,2) = cellstr(B)
db(2:end,3) = cellstr(C)
which generates this output:

Print the name of a variable on upon a plot/figure

Is it possible to refer back to/access the names of variables (say nx1 arrays) that make up a matrix? I wish to access them to insert there names into a plot or figure (as a text) that I have created. Here is an example:
A = [supdamp, clgvlv,redamp,extfanstat,htgvlv,occupied,supfanspd]
%lots of code here but not changing A, just using A(:,:)'s
%drawn figure
text(1,1,'supdamp')
...
text(1,n,'supfanspd')
I have failed in an attempt create a string named a with their names in so that I could loop through a(i,1), then use something like text(1,n,'a(i,1)')
Depending on your problem, it might make sense to use structures with dynamical field names.
Especially if your data in the array have some meaning other than just entries of a matrix in linear algebra sense.
# name your variables so that your grandma could understand what they store
A.('supdamp') = supdamp
A.('clgvlv') = clgvlv
...
fieldsOfA = fieldnames(a)
for n = 1 : numel(fieldsOfA )
text(1, n, fieldsOfA{n})
end

Vectorize filtering on matlab cell structures

I have a huge cell vector cc (size: 1xN) of the form:
cc{1} = {'indexString1', 'str_row1col1', 'str_row1col2' }
cc{2} = {'indexString2', 'str_row2col1', 'bighello', 'str_row1col3' }
cc{3} = {'indexString3','str_row3col1'}
cc{4} = {'indexString4','str_row3col1', 'helloWorld'}
I want to traverse each cell and remove specific cells that contain the word "hello", e.g c{4}{2}. Can we do that without for loops keeping the final structure of cc?
Best,
Thoth.
EDIT: From the answers and comments I have seen that the structure of the cell impose some limitations. So any other suggestion to store my data are welcome. I just want to keep together all the cells (e.g. 'str_row1col1', 'str_row1col2') that correspond to the same indexString*n* (e.g. indexString1). I made this edit in case it helps some final reshape.
Using regular expressions, you can obtain a logical array in which zeros represent occurences of the word 'hello' somewhere in the nested cell. As #LuisMendo pointed out, this would be much easier to delete the unwanted cells if they were not nested:
clc
clear
cc{1} = {'str_row1col1', 'str_row1col2' };
cc{2} = {'str_row2col1', 'bighello', 'str_row1col3' };
cc{3} = {'str_row3col1'};
cc{4} = {'str_row3col1', 'helloWorld'};
A = (cellfun(#isempty,regexp([cc{:}],'(\w*hello|hello\w*)','match')))
Gives the following array:
A =
1 1 1 0 1 1 1 0
For the rest I think you would need a loop since the nested cells are not all of the same size. Anyhow I hope it helps you a bit.
EDIT Here is what you can do using a for loop. In order to identify words of interest (earth and water as in your comment below), simply add them to the argument in the call to regexp. This character: | is used to make some sort of list so that Matlab checks all the expressions in the brackets.
Please refer to this page for more infos on regular expressions. There is also a possibility to look for regular expressions with case-sensitivity.
Sample code, in which I added strings containing earth and water:
cc{1} = {'str_row1col1', 'earth!superman' 'str_row1col2' 'DummyString'};
cc{2} = {'str_row2col1', 'bighello', 'str_row1col3' };
cc{3} = {'str_row3col1' 'str_row3col3' 'water_batman'};
cc{4} = {'str_row3col1' 'str_row4col2' 'helloWorld'};
cc{5} = {'str_row5_LegoMan' 'str_row5col2' 'AnotherDummyString' 'Useless String' 'BonjourWorld'};
% With a for loop, for example:
FinalCell = cell(size(cc,2),1);
for k = 1:size(cc,2)
DummyCell = cc{k}; % Use dummy cell for easier indexing
% This is where you tell Matlab what words/expressions you are looking for
A = cellfun(#isempty,regexp(cc{k},'(\w*hello|hello\w*|earth|water)','match'));
DummyCell(~A) = []; % Remove the cells containing the strings/words of interest
FinalCell{k} = DummyCell;
end
Then you're good to go. Hope that helps!
The closest thing possible I found is:
clear all
cc{1} = {'str_row1col1', 'str_row1col2' };
cc{2} = {'str_row2col1', 'bighello', 'str_row1col3' };
cc{3} = {'str_row3col1'};
cc{4} = {'str_row3col1', 'helloWorld'};
cc1 = [cc{:}];
cc1 = cc1(~strcmp('bighello',cc1));
This reorganize your array into a one dimensional array and it cannot match regular expression, but only whole words.
For a better job I am afraid you have to use for loops.

Outputting data from for loop to .mat file using numbers in title MATLAB

I need to output .mat files for the below data. I need one file to have cell (1,1) to be Mean_RPM_list1, cell (2,1) to be Mean_RPM_list2 etc. And then I need another file to have cell(1,1) to be Mean_Torque_list1 to have cell(1,1).....and so on.
Can anybody shed any light on this for me?
Also if someone knows how to automate me calling the matrices A and B so I could have A = [Mean_rpm1:Mean_rpmMAX], that would also be very helpful.
TIA for any help.
A = [Mean_rpm1 Mean_rpm2 Mean_rpm3 Mean_rpm4 Mean_rpm5 Mean_rpm6 Mean_rpm7 Mean_rpm8 Mean_rpm9 Mean_rpm10 Mean_rpm11 Mean_rpm12];
B = [Mean_torque1 Mean_torque2 Mean_torque3 Mean_torque4 Mean_torque5 Mean_torque6 Mean_torque7 Mean_torque8 Mean_torque9 Mean_torque10 Mean_torque11 Mean_torque12];
plot(A,B,'*')
for i = 1:num_bins;
bin = first + ((i-1)/10);
eval(sprintf('Mean_RPM_list%0.f = A;',bin*10));
eval(sprintf('Mean_Torque_list%0.f = B;',bin*10));
end
First of all this is really bad idea to create a set of variables with names different by numbers. As you can see it's very difficult to deal with such variables, you always have to use eval (or other related) statements.
It's much easier to create a cell array Mean_rpm and access its elements as Mean_rpm{1}, etc.
If the vectors are numeric and have the same size you can also make a 2D/3D array. Then access as Mean_rpm(:,:,1) etc.
Next, to store a cell array to a mat-file you have to create this array in MATLAB. No options (at least for now) to do it by parts in a loop. (But you can do it for numeric vectors and matrices using matfile object.) So why do you need this intermediate Mean_RPM_list variable? Just do Mean_RPM_list{bin*10} = A in your loop.
For your first question, if you already have those variables you have to use eval in a loop. Something like
A = [];
for k=1:K
eval(sprintf('A{k} = [A, Mean_rpm%d];',k));
end
You can also get names for all similar variables and combine them.
varlist = who('Mean_rpm*');
A = cell(1,numel(varlist);
for k = 1:numel(varlist)
eval('A{k} = varlist{k};');
end
Here is one without loop using CELL2FUN:
A=cellfun(#(x)evalin('base',x),varlist,'UniformOutput',0);
You should avoid having all these individual variables around in the first place. Data types like arrays, cell arrays and structure arrays exist to help you with this. If you want each variable to be associated with a name, you can use a structure array. I've made an example below. Instead of assigning a value to Mean_rpm1 like you are doing now, assign it to meanStruct.Mean_rpm1 then save the entire structure.
% as you generate values for each variable, assign them to the
% appropriate field.
meanStruct.Mean_rpm1 = [10:10];
meanStruct.Mean_rpm2 = [12:15];
meanStruct.Mean_rpm3 = [13:20];
meanStruct.Mean_rpm4 = [14];
meanStruct.Mean_rpm5 = [15:18];
meanStruct.Mean_rpm6 = [16:20];
meanStruct.Mean_rpm7 = [17:22];
meanStruct.Mean_rpm8 = [18:22];
meanStruct.Mean_rpm9 = [19:22];
meanStruct.Mean_rpm10 = [20:22];
meanStruct.Mean_rpm11 = [21:22];
meanStruct.Mean_rpm12 = [22:23];
% save the structure array
save('meanValues.mat','meanStruct')
% load and access the structure array
clear all
load('meanValues.mat')
temp = meanStruct.Mean_rpm3

creating variables from structures in matlab

I have the following example which expresses the type of problem that I'm trying to solve:
clear all
textdata = {'DateTime','St','uSt','Ln','W'};
data = rand(365,4);
Final = struct('data',data,'textdata',{textdata})
clear textdata data
From this, Final.data contains values which correspond to the headings in Final.textdata excluding the first ('DateTime') thus Final.data(:,1) corresponds to the heading 'St'... and so on. What I'm trying to do is to create a variable in the workspace for each of these vectors. So, I would have a variable for St, uSt, Ln, and W in the workspace with the corresponding values given in Final.data.
How could this be done?
Will this solve your problem:
for ii=2:length( textdata )
assignin('base',Final.textdata{ii},Final.data(:,ii-1));
end
Let me know if I misunderstood.
The direct answer to your question is to use the assignin function, like so (edit: just like macduff suggested 10 minutes ago):
%Starting with a Final structure containing the data, like this
Final.textdata = {'DateTime','St','uSt','Ln','W'};
Final.data = rand(365,4);
for ix = 1:4
assignin('base',Final.textdata{ix+1}, Final.data(:,ix));
end
However, I strongly discourage using dynamic variable names to encode data like this. Code that starts this way usually ends up as spaghetti code full of long string concatenations and eval statements. Better is to use a structure, like this
for ix = 1:4
dataValues(Final.textdata{ix+1}) = Final.data(:,ix);
end
Or, to get the same result in a single line:
dataValues = cell2struct(num2cell(Final.data,1), Final.textdata(2:end),2)