MATLAB missorting structure array when using dir command - matlab

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

Related

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

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.

Sequential import of datafiles according to rule in Matlab

I have a list of .txt datafiles to import. Suppose they are called like that
file100data.txt file101data.txt ... file109data.txt I want to import them all using readtable.
I tried using the for to specify a vector a = [0:9] through which matlab could loop the readtable command but I cannot make it work.
for a = [0:9]
T_a_ = readtable('file10_a_data.txt')
end
I know I cannot just put _a_ where I want the vector to loop through, so my question is how can I actually do it?
Thank you in advance!
Here is a solution that should work even if you have missing files in your folder (e.g. you have file100data.txt to file107data.txt, but you are missing file file108data.txt and file109data.txt):
files=dir('file10*data.txt'); %list all data files in your folder
nof=size(files,1); %number of files
for i=1:nof %loop over the number of files
table_index=files(i).name(7) %recover table index from data filename
eval(sprintf('T%s = readtable(files(i).name)', table_index)); %read table
end
Now, please note that is it generally regarded as poor practice to dynamically name variables in Matlab (see this post for example). You may want to resort to structures or cells to store your data.
You need to convert the value of a into a string and combine strings together, like this:
Tables = struct();
for a = 0:9
% note: using dynamic structure field names to store the imported tables
fname = ['file10_' num2str(a) '_data'];
Tables.(fname) = readtable([fname '.txt']);
end

Export data to same CSV file for multiple runs of .m file

I am running a MATLAB program and storing the results in two matrices. For each run of the program, those matrices are written to the same .csv file.
How can I continue to store data to the same file for future runs of the program? Is there a function that checks for data already being present to avoid overwriting cells?
t = 0.0001*[0:70];
v = B_2*R_R.*exp(-alpha.*t).*sin(omega_d.*t);
tv = [t; v].';
csvwrite('thedata.csv',tv,3,0)
I couldn't resist rewriting your code a bit.
This should be equivalent to what you have, and print both vectors to thedata.csv.
t = 0.0001*[0:70];
v = B_2*R_R.*exp(-alpha.*t).*sin(omega_d.*t);
tv = [t; v].';
csvwrite('thedata.csv',tv,3,0)
Due to the way csv-files are stored, you can only append data at the end of the file, which happens to be the bottom row, not the last column. What you should do, is concatenate all data before writing to the csv-file. That way you avoid multiple calls to csvwrite or dlmwrite (they are time consuming).
If that's impossible, then I suggest reading the data from the csv-file, using csvread, append the new data to the data you retrieve, and write it all back again.
csvwrite('thedata.csv',tv)
mydata = csvread('thedata.csv');
mydata2 = [mydata, tv2];
csvwrite('thedata.csv',mydata2)

Modifying output names using for in Matlab

I'm trying to change output names using for in Matlab. I'm reading daily files, so I'd like the outputs to also have the day printed on their name. This is a simplification of what I've got so far:
day=['1','2','3','4','5'];
for i=1:length(day)
namefile=['datafromday',num2str(day(i)),'.nc'];
[var1,var2,var3]=read(namefile);
var1_*=var1;
var2_*=var2;
var3_*=var3;
end
The * marks where I want to have the day number on. I've tried the same combination as in namefile but was unsuccessful.
Any ideas? Thank you!
I suggest you use a 2D cell array instead of separate variables. First index of the cell array will correspond to day, second will correspond to namefile. (Also, don't use var as a variable name, as there is a function with that name).
day = ['1','2','3','4','5'];
vars = cell(numel(day),3); %// change "3" as needed
for i = 1:length(day)
namefile = ['datafromday',num2str(day(i)),'.nc'];
[vars{i,:}] = read(namefile);
%// Now the file names are in vars{i,1}, vars{i,2} etc
end

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.