0

This function reads the data from multiple mat files and save them in multiple txt files. But the data (each value) are saved one value in one column and so on. I want to save the data in a form of three columns (coordinates) in the text files, so each row has three values separated by space. Reshape the data before i save them in a text file doesn't work. I know that dlmwrite should be modified in away to make newline after three values but how?

mat = dir('*.mat'); 
for q = 1:length(mat) 
   load(mat(q).name);
   [~, testName, ~] = fileparts(mat(q).name);
   testVar = eval(testName); 
   pos(q,:,:) = testVar.Bodies.Positions(1,:,:);
   %pos=reshape(pos,2,3,2000);
   filename = sprintf('data%d.txt', q);
   dlmwrite(filename  , pos(q,:,:), 'delimiter','\t','newline','pc')
 end

My data structure: The data in rectangle are interested

These data should be extracted from each mat file and stored in the corresponding text files like this:

332.68    42.76   42.663  3.0737  
332.69    42.746  42.655  3.0739  
332.69    42.75   42.665  3.074 
max
  • 3,915
  • 2
  • 9
  • 25
kamel
  • 15
  • 6
  • Please see [this answer of mine](https://stackoverflow.com/a/32467170/5211833) and references therein. If it's possible to avoid using `eval`, which it is, see max' answer, avoid using it. There's a large host of problems associated with it (extreme performance losses due to JIT disabling, code obscurity, potential harm up to formatting your entire computer etc). – Adriaan Nov 26 '20 at 11:59
  • Please stop editing your questions by changing them significantly. Not when invalidating existing answers, but neither to suddenly add a completely unrelated language. That would make your question too broad for the site btw, since what would be next, C#? Java? PHP? Please take the [tour], read up on [ask] and stay within the limits and rules outlined therein. – Adriaan Nov 26 '20 at 13:08
  • Okey, i will not change the question. I am new on Stackoverflow :) – kamel Nov 26 '20 at 13:28

2 Answers2

1

A TheMathWorks-trainer once told me that there is almost never a good reason nor a need to use eval. Here's a snippet of code that should solve your writing problem using writematrix since dlmwrite is considered to be deprecated.

It further puts the file-handling/loading on a more resilient base. One can access structs dynamically with the .(FILENAME) notation. This is quite convenient if you know your fields. With who one can list variables in the workspace but also in .mat-files!

Have a look:

% path to folder
pFldr = pwd;

% get a list of all mat-files (returns an array of structs)
Lst = dir( fullfile(pFldr,'*.mat') );

% loop over files
for Fl = Lst.'
    % create path to file
    pFl = fullfile( Fl.folder, Fl.name );
    % variable to load 
    [~, var2load, ~] = fileparts(Fl.name);
    
    % get names of variables inside the file
    varInfo = who('-file',pFl);
    % check if it contains the desired variables
    if ~all( ismember(var2load,varInfo) )
        % display some kind of warning/info
        disp(strcat("the file ",Fl.name," does not contain all required varibales and is therefore skipped."))
        % skip / continue with loop
        continue
    end
    % load | NO NEED TO USE eval()
    Dat = load(pFl, var2load);
    
    % DO WHATEVER YOU WANT TO DO
    pos = squeeze( Dat.(var2load)(1,:,1:2000) );
    
    % create file name for text file
    pFl2save = fullfile( Fl.folder, strrep(Fl.name,'.mat','.txt') );
    writematrix(pos,pFl2save,'Delimiter','\t')
end

To get your 3D-matrix data into a 2D matrix that you can write nicely to a file, use the function squeeze. It gets rid of empty dimensions (in your case, the first dimension) and squeezes the data into a lower-dimensional matrix

max
  • 3,915
  • 2
  • 9
  • 25
  • Hey, Thank you for your answer. The variable which i want are inside the positions in the Rigidbodies inside the file name (Filename.RigidBodies.Positions), so i write it as following pos = Dat.RigidBodies.Positions(var2load)(1,:,:); I got an error (Indexing with parentheses '()' must appear as the last operation of a valid indexing expression) at pos after the comment (do whatever you want to do) – kamel Nov 26 '20 at 11:42
  • See please my data structure – kamel Nov 26 '20 at 11:56
  • Don't forget the dot before the brackets: `Dat.RigidBodies.Positions.(var2load)(1,:,:);`. If you use such a nested structure, it will be hard to make use of `who`. You example suggested that `testName` is also the name of the variable that you want to load and index (sorry, I won't download data from unknown sources) – max Nov 26 '20 at 14:59
  • How can i do it in my case with who or another? My code works with writematix or dlmwrite but each value is located in a column. You don't need to download the date :) , it is just a picture :) , i didn't upload my data since it is not necessary. The RigidBodies.Positions stays the same in all files. The number in file name changes just. – kamel Nov 26 '20 at 18:36
  • The picture doesn't show the data structure. If it is just a 3D-variable, you can use `who` as I showed you. To get your data formatted into a 2D matrix from a 3D matrix, use [`squeeze`](https://www.mathworks.com/help/matlab/ref/squeeze.html) – max Nov 27 '20 at 07:10
0

Why don't you use writematrix() function?

mat = dir('*.mat'); 
for q = 1:length(mat) 
   load(mat(q).name);
   [~, testName, ~] = fileparts(mat(q).name);
   testVar = eval(testName); 
   pos(q,:,:) = testVar(1,:,1:2000);
   filename = sprintf('data%d.txt', q);
   writematrix(pos(q,:,:),filename,'Delimiter','space');
 end

More insight you can find here: https://www.mathworks.com/help/matlab/ref/writematrix.html