matlabloopsmergexyz

Merge all data from xyz files in Matlab


I have a set of 501 XYZ files which I load in as

for k = 1:501

    % AIS SEC data

    AIS_SEC{k} = importdata(['AIS_SEC(' num2str(k) ').xyz']);

end

This generates an 1x501 cell array in which all data are stored (I uploaded this file as in attachment at https://nl.mathworks.com/matlabcentral/answers/486579-how-to-merge-multiple-xyz-files-into-1-large-array). How can I merge all these data to have 1 large XYZ file? The ultimate goal is the have a nx3 array where all of the data from the seperate xyz files are merged in to 1.

For example, to concentrate X data, I tried:

for k = 1:501
    my_field = sprintf('X%d', k);
    variable.(my_field) = ([AIS_SEC{1,k}.data(:,1)]);
end

BUT: Dot indexing is not supported for variables of this type.

Thanks!


Solution

  • There are several wrong things with your code:

    First thing, the error Struct contents reference from a non-struct array object. shows up first at index k=33 because the structure imported has no data field (the import was probably empty or failed).

    Checking for the presence of the field let the code run through to completion. You'll then notice that you have 8 rows which are empty.

    load('AIS_SEC.mat')
    n=numel(AIS_SEC) ;
    EmptyRows = false(n,1) ;
    for k = 1:n
        my_field = sprintf('X%03d', k);
        if isfield( AIS_SEC{1,k} , 'data')
            variable.(my_field) = AIS_SEC{1,k}.data;
        else
            variable.(my_field) = [] ;
            EmptyRows(k) = true ;
        end
    end
    fprintf('Number of empty rows encountered: %u\n',sum(EmptyRows))
    

    I took the liberty to also remove unnecessary parenthesis, added an empty row index counter, and adjusted the sprintf output format so all your field will have the same length (even the first field will have the leading zeros. 'X001' to 'X500' instead of 'X1' to 'X500').

    Also, this was only retrieving the first column out of each structure, so I modified it to retrieve the 3 x,y,z columns. If you really wanted only the first column, just replace variable.(my_field) = AIS_SEC{1,k}.data by variable.(my_field) = AIS_SEC{1,k}.data(:,1).


    Now this gives you a long structure with 500 fields (each representing one imported variable). Your question is not clear enough on that point but if you want to have a single array where all the values are merged, then you have 2 options:

    1) Directly after the code above, convert your structure to a merged array:

    vararray = cell2mat(struct2cell(variable)) ;
    

    2) If the steps above (the final variable structure) is not something you need to keep, then you can avoid it in the first place:

    load('AIS_SEC.mat')
    n = numel(AIS_SEC) ;        % number of field to import
    
    % first pass we count how many data point (if any) each structure has
    EmptyRows = false(n,1) ;    
    npts      = zeros(n,1) ;
    for k = 1:n
        if isfield( AIS_SEC{1,k} , 'data')
            npts(k) = size( AIS_SEC{1,k}.data , 1 ) ;
        else
            EmptyRows(k) = true ;
        end
    end
    % fprintf('Number of empty rows encountered: %u\n',sum(EmptyRows))
    
    % The above allows us to preallocate the output matrix at the right size
    cumpts = cumsum(npts) ;
    totalNumberOfPoints = cumpts(end) ;
    vararray = zeros(totalNumberOfPoints,3) ;
    
    % first field to import
    vararray( 1:cumpts(1) , : ) =  AIS_SEC{1,1}.data ;
    % now all the remaining ones
    for k =  2:n
        idx = (cumpts(k-1)+1):cumpts(k) ;
        if ~isempty(idx)
            vararray(idx,:) = AIS_SEC{1,k}.data ;
        end
    end
    

    In this version there are 2 passes of the loop accross the structure. Counter intuitively this is done for better performances. The first pass is only to count the number of data points in each structure (and also to flag the empty ones). Thanks to the number returned by the first pass, we can preallocate the output matrix before the second pass and assign each structure data to the merged array in the right place without having to resize the output array at each iteration.