"Dot indexing is not supported for variables of this type" for a code that was running perfectly fine? - matlab

I have some MATLAB code that I worked on with someone who is much more experienced in MATLAB than I am. The code was running perfectly fine the other day. When I tried running it today, I got the error "Dot indexing is not supported for variables of this type" and I have tried reading through many other stack overflow questions on the topic, but still struggling to resolve my issue. I will include the code up until the error below. Based on what I've read, it might be something to do with structure? I would appreciate any help or tips you could send my way. Thank you!
for j = 3:length(files)
files(j).name
folder_name = files(j).folder;
file2load = strcat(folder_name, '\', files(j).name);
data_input = load(file2load);
trace_names = fieldnames(data_input);
for i = 1:length(trace_names)
data_to_plot.x = data_input.(char(trace_names(i))).data.x;
data_to_plot.y = data_input.(char(trace_names(i))).data.y;

As the comments point out, it is not clear why you are getting this error, but I can tell you what is causing it. 'Dot indexing' is a way of accessing data fields in a type of Matlab variable called a struct. In your snippet files(j) is not a struct.
For example, you cannot do this:
>> s = {}; % s is a cell array (not a struct)
>> g = {};
>> g{1} = 'lala';
>> s{1} = g;
>> s.g % cannot access g using this syntax
Dot indexing is not supported for variables of this type.
But if you make s a struct, you can:
>> s = struct
s =
struct with no fields.
>> s.item1 = g; % create a field called item1 to hold the stuff in g
>> s.item1 % now you can use dot indexing to access the stuff you put in there
ans =
1×1 cell array
{'lala'}
I would guess that this snippet is part of a function where files is an argument or down the line of a script in which files is earlier defined. Probably the other day with your colleague, you had files set to a variable that is indeed an array of structures with the items name etc inside of them. Since then, something changed the value of files to an array of non-struct types.

Related

Only add existing variables in Matlab

I would like to add the sums of 5 one-column arrays in Matlab. The catch is that depending on previous inputs, any of these arrays may or may not exist, thus throwing an error when I try to add the sums of these arrays for post-processing.
After doing some digging I found the following function which I can use to return a logical statement if a certain variable exists in the workspace:
exist('my_variable','var') == 1
I'm not sure this helps me in this case though - Currently the line in which I add the sums of the various arrays looks as follows:
tot_deviation = sum(var1) + sum(var2) + sum(var3) + sum(var4) + sum(var4);
Is there a short way to add only the sums of the existing arrays without excessive loops?
Any help would be appreciated!
You can use if statements:
if ~exist('var1','var'), var1 = 0;end
if ~exist('var2','var'), var2 = 0;end
if ~exist('var3','var'), var3 = 0;end
if ~exist('var4','var'), var4 = 0;end
tot_deviation = sum(var1) + sum(var2) + sum(var3) + sum(var4) + sum(var4);
To my knowledge there is no quick way to do this in matlab. It seems to me that, depending on the structure of your code, you have the following alternatives:
1- Initialize all your variables to column arrays of zeros with something like
var = zeros(nbLines, 1);
2- Put all your columns vectors side to side in a single array and the use tot_deviation = sum(sum(MyArray)); which will work no matter how many columns and lines there is in the array.
3- If you pass your variables to a function you can check the number of inputs arguments inside the function using 'nargin' and then only proceed to sum the right number of variables.
I would recommend using the second method for it seem to me that it is the one that allows you to take the most advantage of matlab's array system which good.
The most robust solution is to initialise all of your variables to 0 at the top of the function. Then there is no chance they don't exist, and they influence the summation correctly.
Alternatively...
You could (read: shouldn't) use a really nasty eval trick here for flexibility...
vars = {'var1','var2','var3','var4'};
tot = 0;
for ii = 1:numel(vars)
if exist(vars{ii}, 'var')
tot = tot + eval(var);
end
end
I say it's "nasty" because eval should be avoided (read the linked blog). The check on the variable name existence mitigates some of the strife, but it's still not ideal.
As suggested in the MathWorks blog on evading eval, a better option would be a struct with dynamic field names. You could use almost the same syntax as above, but replace the if statement with
if isfield( myStruct, vars{ii} )
tot = tot + myStruct.(vars{ii});
end
This will avoid dynamically named variables and keep your workspace clean!

Matlab: how to rename a sub-field

Let me describe the question in this way. I have a .mat file, and if I open it, it contains a 1x10 struct data. In each data, it has a 1x5 struct (or field) called res. In res, it has a 1x1 struct (or field) called, let's say, foo. Thus, I have ixj copies of data(i).res(j).foo .
Is there anyway I can change the name of this foo? say I want all data(i).res(j).foo to become data(i).res(j).bar
I did search on the internet, and tried a few ways (add field and delete, create a temp field, use cell2field or fieldtofile, etc.) and all of them didn't work. The most frequent returned error is "Subscripted Assignment between dissimilar structures."
Please help, thanks in advance!
The safest way is probably by looping over data twice, the first pass creating a new field bar for each subfield like data(i).res(j).bar=data(i).res(j).foo, then the second pass deletes the old fields like data(i).res(j) = rmfield(data(i).res(j),'foo').
Thanks caoy and NotLikeThat. I finally came to an conclusion.
data2 = data
for i=1:10
for j = 1:5
data(i).res(j).bar = data2(i).res(j).foo;
end
data(i).res = rmfield(data(i).res, 'foo');
end
I probably need to removed i, j, and data2 after running this script.

Matlab: dynamic name for structure

I want to create a structure with a variable name in a matlab script. The idea is to extract a part of an input string filled by the user and to create a structure with this name. For example:
CompleteCaseName = input('s');
USER WRITES '2013-06-12_test001_blabla';
CompleteCaseName = '2013-06-12_test001_blabla'
casename(12:18) = struct('x','y','z');
In this example, casename(12:18) gives me the result test001.
I would like to do this to allow me to compare easily two cases by importing the results of each case successively. So I could write, for instance :
plot(test001.x,test001.y,test002.x,test002.y);
The problem is that the line casename(12:18) = struct('x','y','z'); is invalid for Matlab because it makes me change a string to a struct. All the examples I find with struct are based on a definition like
S = struct('x','y','z');
And I can't find a way to make a dynamical name for S based on a string.
I hope someone understood what I write :) I checked on the FAQ and with Google but I wasn't able to find the same problem.
Use a structure with a dynamic field name.
For example,
mydata.(casename(12:18)) = struct;
will give you a struct mydata with a field test001.
You can then later add your x, y, z fields to this.
You can use the fields later either by mydata.test001.x, or by mydata.(casename(12:18)).x.
If at all possible, try to stay away from using eval, as another answer suggests. It makes things very difficult to debug, and the example given there, which directly evals user input:
eval('%s = struct(''x'',''y'',''z'');',casename(12:18));
is even a security risk - what happens if the user types in a string where the selected characters are system(''rm -r /''); a? Something bad, that's what.
As I already commented, the best case scenario is when all your x and y vectors have same length. In this case you can store all data from the different files into 2 matrices and call plot(x,y) to plot each column as a series.
Alternatively, you can use a cell array such that:
c = cell(2,nufiles);
for ii = 1:numfiles
c{1,ii} = import x data from file ii
c{2,ii} = import y data from file ii
end
plot(c{:})
A structure, on the other hand
s.('test001').x = ...
s.('test001').y = ...
Use eval:
eval(sprintf('%s = struct(''x'',''y'',''z'');',casename(12:18)));
Edit: apologies, forgot the sprintf.

MATLAB missorting structure array when using dir command

I have a bunch of Excel data, called "1.xls", "2.xls"... until "15.xls", each with 141x44 sets of data. I am using the dir function to import the data into MATLAB.
Here I am importing the first and second columns from each file into A and B matrix.
prob15 = dir(fullfile('C:\Users\Bo Sun\Documents\MATLAB\prob15'),'.xls');
global A B
A=zeros(141,length(prob15));
B=zeros(141,length(prob15));
for i=1:length(prob15)
A(:,i) = xlsread(prob15(i).name,'A:A');
B(:,i) = xlsread(prob15(i).name,'B:B');
end
My problem is, when I use the dir command, for some reason MATLAB missorts the data, in that the ascending order of the prob15 structure array will be "1.xls", "10.xls", "11.xls"... instead of normal ascending numerical order ("1.xls", "2.xls, ...). Anyone know how I could fix this? Thanks.
The order you are seeing is called ascii-betical order and is the normal sorting order for all kinds of utilities, and evidently your OS directory listing program as well, since matlab just farms this command out to the OS.
If you want a numerical sort, you can convert the filename strings to numbers and sort those. Before I wrote it myself some light googling yielded this which you can easily adapt to your problem:
list = dir(fullfile(cd, '*.mat'));
name = {list.name};
str = sprintf('%s#', name{:});
num = sscanf(str, 'r_%d.mat#');
[dummy, index] = sort(num);
name = name(index);

Reading input m-file in a main m-file

I would like MATLAB to tell me if I have an input file (.m file) that contains some variables with their numbers (i.e., a = 5, b = 6, c = 7) so that I can then use that .m file in another program (main .m file) that uses these variables to calculate S = a + b + c. How can I then read the input file from the main file? Assume the input file is called INP and the main MAIN.
This is typically not good practice in MATLAB. The file containing the input variables would, in your example, be a script. As would your main file. MATLAB does not error when running one script from another, as suggested by ScottieT812, but under certain circumstances strange errors can arise. (Run time compiling has difficulty, variable name collisions across scripts)
A better option is to turn the inputs script into a function which returns the variables of interest
function [a,b c] = inputs
a = 5;
b = 6;
c = 7;
Then this function can be called in the main.m script.
% main.m
[a,b,c] = inputs;
s = a+b+c;
If your "input" file is an m-file, just use the name of the file in your "main" m-file. For example you might have a file called input.m that looks like this:
% File: inputs.m
a = 5;
b = 6;
c = 7;
Then, you can use it in the file main.m like this:
% File: main.m
inputs;
S = a + b + c;
For this sort of stuff (parameters that are easily adjusted later) I almost always use structures:
function S = zark
S.wheels = 24;
S.mpg = 13.2;
S.name = 'magic bus';
S.transfer_fcn = #(x) x+7;
S.K = [1 2; -2 1];
Then you can return lots of data without having to do stuff like [a,b,c,d,e,f]=some_function;
One nice thing about structures is you can address them dynamically:
>> f = 'wheels';
>> S.(f)
ans =
24
It sounds like you want to have some global configuration information that's used by scripts. Often, it's much better to create functions and pass values as arguments, but sometimes it makes sense to do things the way you suggest. One way to accomplish this is to save the information in a file. See "load" and "save" in the Matlab documentation.
I ran into the exact problem KennyMorton mentioned when trying to create runtime compiled versions of MATLAB software for my work. The software uses m-files extensively for passing arguments between functions. Additionally, we create these m-files dynamically which the deployed version of MATLAB does not play nice with. Our workaround was:
save the parameters to a file without the .m extension
read and eval the contents of the file
So, to follow the OPs example, in a function we would create a text file, INP, containing our parameters. We create this file in the directory returned by the ctfroot function. Then, in MAIN, we would use the following to retrieve these parameters:
eval(char(textread(fullfile(ctfroot, INP), '%s', 'whitespace', '');
If the data script is just a script, you can call it from a function or another script directly. Not extra commands required. For example:
%mydata.m
a = 1;
b = 2;
%mymain.m
mydata
whos
mymain
>>mymain
Name Size Bytes Class Attributes
a 1x1 8 double
b 1x1 8 double
This also works for functions in addition to scripts
%foo.m
function foo
mydata
whos
>>foo
Name Size Bytes Class Attributes
a 1x1 8 double
b 1x1 8 double
Generally, it is preferable to use a MAT or other data file for this sort of thing.